All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCHv1 00/17] Bluetooth A2MP implementation
@ 2012-05-18 14:25 Andrei Emeltchenko
  2012-05-18 14:25 ` [PATCHv1 01/17] Bluetooth: A2MP: Create A2MP channel Andrei Emeltchenko
                   ` (20 more replies)
  0 siblings, 21 replies; 104+ messages in thread
From: Andrei Emeltchenko @ 2012-05-18 14:25 UTC (permalink / raw)
  To: linux-bluetooth

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

Basic A2MP implementation.

Changes:
	* PATCHv1: Rebasing against latest tree and minor fixes.
	* RFCv7: Taking comments from review in linux-bluetooth.
	* RFCv6: Remove some unneded check for sk since they are in different path
	(A2MP decoded as a data channel wrt L2CAP signalling channel). Style fixes.
	* RFCv5: Fix memory leaks, sparse warnings and taking comments from upstream.
	* RFCv4: redesign code to use l2cap channel lock instead of socket lock
	and general modifications. Basic implementation of HCI callback interface.
	* RFCv3: redesign code to use l2cap functions instead of kernel sockets
	L2CAP functions modified to work with channels without sk.
	* RFCv2: rebased against "workqueue" patches.
	* RFCv1: added refcnt to amp_mgr, fixed sleeping in atomic

Initially code was based of reference implementations below:

References: Code Aurora (git://codeaurora.org/kernel/msm.git) and Atheros
(search for: [PATCH 2/3] Add a2mp protocol/AMP manager, by Atheros Linux BT3)
implementations.

Andrei Emeltchenko (17):
  Bluetooth: A2MP: Create A2MP channel
  Bluetooth: A2MP: AMP Manager basic functions
  Bluetooth: A2MP: Build and Send msg helpers
  Bluetooth: A2MP: Add chan callbacks
  Bluetooth: A2MP: Definitions for A2MP commands
  Bluetooth: A2MP: Define A2MP status codes
  Bluetooth: A2MP: Process A2MP messages
  Bluetooth: A2MP: Process A2MP Command Reject
  Bluetooth: A2MP: Process A2MP Discover Request
  Bluetooth: A2MP: Process A2MP Change Notify
  Bluetooth: A2MP: Process A2MP Get Info Request
  Bluetooth: A2MP: Process A2MP Get AMP Assoc Request
  Bluetooth: A2MP: Process A2MP Create Physlink Request
  Bluetooth: A2MP: Process A2MP Disc Physlink Request
  Bluetooth: A2MP: Process A2MP Command Responses
  Bluetooth: A2MP: Handling fixed channels
  Bluetooth: A2MP: Manage incoming connections

 include/net/bluetooth/a2mp.h     |  127 +++++++++
 include/net/bluetooth/hci_core.h |   14 +
 include/net/bluetooth/l2cap.h    |    6 +
 net/bluetooth/Makefile           |    3 +-
 net/bluetooth/a2mp.c             |  558 ++++++++++++++++++++++++++++++++++++++
 net/bluetooth/hci_conn.c         |   15 +
 net/bluetooth/l2cap_core.c       |   43 ++-
 7 files changed, 757 insertions(+), 9 deletions(-)
 create mode 100644 include/net/bluetooth/a2mp.h
 create mode 100644 net/bluetooth/a2mp.c

-- 
1.7.9.5


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

* [PATCHv1 01/17] Bluetooth: A2MP: Create A2MP channel
  2012-05-18 14:25 [PATCHv1 00/17] Bluetooth A2MP implementation Andrei Emeltchenko
@ 2012-05-18 14:25 ` Andrei Emeltchenko
  2012-05-22 17:45   ` Mat Martineau
  2012-05-18 14:25 ` [PATCHv1 02/17] Bluetooth: A2MP: AMP Manager basic functions Andrei Emeltchenko
                   ` (19 subsequent siblings)
  20 siblings, 1 reply; 104+ messages in thread
From: Andrei Emeltchenko @ 2012-05-18 14:25 UTC (permalink / raw)
  To: linux-bluetooth

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

Create and initialize fixed A2MP channel

Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
 include/net/bluetooth/l2cap.h |    5 ++++
 net/bluetooth/Makefile        |    3 ++-
 net/bluetooth/a2mp.c          |   59 +++++++++++++++++++++++++++++++++++++++++
 net/bluetooth/l2cap_core.c    |    4 +--
 4 files changed, 68 insertions(+), 3 deletions(-)
 create mode 100644 net/bluetooth/a2mp.c

diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index 8fdfaca..8cc739f 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -52,6 +52,8 @@
 #define L2CAP_CONN_TIMEOUT		msecs_to_jiffies(40000)
 #define L2CAP_INFO_TIMEOUT		msecs_to_jiffies(4000)
 
+#define L2CAP_A2MP_DEFAULT_MTU		670
+
 /* L2CAP socket address */
 struct sockaddr_l2 {
 	sa_family_t	l2_family;
@@ -232,6 +234,7 @@ struct l2cap_conn_rsp {
 /* channel indentifier */
 #define L2CAP_CID_SIGNALING	0x0001
 #define L2CAP_CID_CONN_LESS	0x0002
+#define L2CAP_CID_A2MP		0x0003
 #define L2CAP_CID_LE_DATA	0x0004
 #define L2CAP_CID_LE_SIGNALING	0x0005
 #define L2CAP_CID_SMP		0x0006
@@ -931,5 +934,7 @@ int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len,
 void l2cap_chan_busy(struct l2cap_chan *chan, int busy);
 int l2cap_chan_check_security(struct l2cap_chan *chan);
 void l2cap_chan_set_defaults(struct l2cap_chan *chan);
+int l2cap_ertm_init(struct l2cap_chan *chan);
+void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan);
 
 #endif /* __L2CAP_H */
diff --git a/net/bluetooth/Makefile b/net/bluetooth/Makefile
index 2dc5a57..fa6d94a 100644
--- a/net/bluetooth/Makefile
+++ b/net/bluetooth/Makefile
@@ -9,4 +9,5 @@ obj-$(CONFIG_BT_CMTP)	+= cmtp/
 obj-$(CONFIG_BT_HIDP)	+= hidp/
 
 bluetooth-y := af_bluetooth.o hci_core.o hci_conn.o hci_event.o mgmt.o \
-	hci_sock.o hci_sysfs.o l2cap_core.o l2cap_sock.o smp.o sco.o lib.o
+	hci_sock.o hci_sysfs.o l2cap_core.o l2cap_sock.o smp.o sco.o lib.o \
+	a2mp.o
diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c
new file mode 100644
index 0000000..1f733b5
--- /dev/null
+++ b/net/bluetooth/a2mp.c
@@ -0,0 +1,59 @@
+/*
+   Copyright (c) 2010,2011 Code Aurora Forum.  All rights reserved.
+   Copyright (c) 2011,2012 Intel Corp.
+
+   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.
+*/
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+#include <net/bluetooth/l2cap.h>
+
+static struct l2cap_ops a2mp_chan_ops = {
+	.name = "L2CAP A2MP channel",
+};
+
+static struct l2cap_chan *a2mp_chan_open(struct l2cap_conn *conn)
+{
+	struct l2cap_chan *chan;
+
+	chan = l2cap_chan_create();
+	if (!chan)
+		return NULL;
+
+	BT_DBG("chan %p", chan);
+
+	hci_conn_hold(conn->hcon);
+
+	chan->omtu = L2CAP_A2MP_DEFAULT_MTU;
+	chan->imtu = L2CAP_A2MP_DEFAULT_MTU;
+	chan->flush_to = L2CAP_DEFAULT_FLUSH_TO;
+
+	chan->ops = &a2mp_chan_ops;
+
+	l2cap_chan_set_defaults(chan);
+	chan->remote_max_tx = chan->max_tx;
+	chan->remote_tx_win = chan->tx_win;
+
+	chan->retrans_timeout = L2CAP_DEFAULT_RETRANS_TO;
+	chan->monitor_timeout = L2CAP_DEFAULT_MONITOR_TO;
+
+	skb_queue_head_init(&chan->tx_q);
+
+	chan->mode = L2CAP_MODE_ERTM;
+	l2cap_ertm_init(chan);
+
+	l2cap_chan_add(conn, chan);
+
+	chan->remote_mps = chan->omtu;
+	chan->mps = chan->omtu;
+
+	return chan;
+}
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 65e56d5..ee333f0 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -469,7 +469,7 @@ static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
 	list_add(&chan->list, &conn->chan_l);
 }
 
-static void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
+void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
 {
 	mutex_lock(&conn->chan_lock);
 	__l2cap_chan_add(conn, chan);
@@ -2349,7 +2349,7 @@ static void l2cap_ack_timeout(struct work_struct *work)
 	l2cap_chan_put(chan);
 }
 
-static inline int l2cap_ertm_init(struct l2cap_chan *chan)
+int l2cap_ertm_init(struct l2cap_chan *chan)
 {
 	int err;
 
-- 
1.7.9.5


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

* [PATCHv1 02/17] Bluetooth: A2MP: AMP Manager basic functions
  2012-05-18 14:25 [PATCHv1 00/17] Bluetooth A2MP implementation Andrei Emeltchenko
  2012-05-18 14:25 ` [PATCHv1 01/17] Bluetooth: A2MP: Create A2MP channel Andrei Emeltchenko
@ 2012-05-18 14:25 ` Andrei Emeltchenko
  2012-05-18 14:25 ` [PATCHv1 03/17] Bluetooth: A2MP: Build and Send msg helpers Andrei Emeltchenko
                   ` (18 subsequent siblings)
  20 siblings, 0 replies; 104+ messages in thread
From: Andrei Emeltchenko @ 2012-05-18 14:25 UTC (permalink / raw)
  To: linux-bluetooth

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

Define AMP Manager and some basic functions.

Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
 include/net/bluetooth/a2mp.h     |   31 ++++++++++++++++++++++
 include/net/bluetooth/hci_core.h |    1 +
 net/bluetooth/a2mp.c             |   54 ++++++++++++++++++++++++++++++++++++++
 net/bluetooth/hci_conn.c         |   15 +++++++++++
 4 files changed, 101 insertions(+)
 create mode 100644 include/net/bluetooth/a2mp.h

diff --git a/include/net/bluetooth/a2mp.h b/include/net/bluetooth/a2mp.h
new file mode 100644
index 0000000..1c55514
--- /dev/null
+++ b/include/net/bluetooth/a2mp.h
@@ -0,0 +1,31 @@
+/*
+   Copyright (c) 2010,2011 Code Aurora Forum.  All rights reserved.
+   Copyright (c) 2011,2012 Intel Corp.
+
+   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 __A2MP_H
+#define __A2MP_H
+
+struct amp_mgr {
+	struct list_head	list;
+	struct l2cap_conn	*l2cap_conn;
+	struct l2cap_chan	*a2mp_chan;
+	struct kref		kref;
+	__u8			ident;
+	__u8			handle;
+	unsigned long		flags;
+};
+
+void amp_mgr_get(struct amp_mgr *mgr);
+int amp_mgr_put(struct amp_mgr *mgr);
+
+#endif /* __A2MP_H */
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 20b7d6b..3d9b07f 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -321,6 +321,7 @@ struct hci_conn {
 
 	struct sk_buff_head data_q;
 	struct list_head chan_list;
+	struct list_head mgr_list;
 
 	struct delayed_work disc_work;
 	struct timer_list idle_timer;
diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c
index 1f733b5..85cd29a 100644
--- a/net/bluetooth/a2mp.c
+++ b/net/bluetooth/a2mp.c
@@ -15,6 +15,7 @@
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
 #include <net/bluetooth/l2cap.h>
+#include <net/bluetooth/a2mp.h>
 
 static struct l2cap_ops a2mp_chan_ops = {
 	.name = "L2CAP A2MP channel",
@@ -57,3 +58,56 @@ static struct l2cap_chan *a2mp_chan_open(struct l2cap_conn *conn)
 
 	return chan;
 }
+
+/* AMP Manager functions */
+void amp_mgr_get(struct amp_mgr *mgr)
+{
+	BT_DBG("mgr %p", mgr);
+
+	kref_get(&mgr->kref);
+}
+
+static void amp_mgr_destroy(struct kref *kref)
+{
+	struct amp_mgr *mgr = container_of(kref, struct amp_mgr, kref);
+
+	BT_DBG("mgr %p", mgr);
+
+	kfree(mgr);
+}
+
+int amp_mgr_put(struct amp_mgr *mgr)
+{
+	BT_DBG("mgr %p", mgr);
+
+	return kref_put(&mgr->kref, &amp_mgr_destroy);
+}
+
+static struct amp_mgr *amp_mgr_create(struct l2cap_conn *conn)
+{
+	struct amp_mgr *mgr;
+	struct l2cap_chan *chan;
+
+	mgr = kzalloc(sizeof(*mgr), GFP_KERNEL);
+	if (!mgr)
+		return NULL;
+
+	BT_DBG("conn %p mgr %p", conn, mgr);
+
+	mgr->l2cap_conn = conn;
+
+	chan = a2mp_chan_open(conn);
+	if (!chan) {
+		kfree(mgr);
+		return NULL;
+	}
+
+	mgr->a2mp_chan = chan;
+	chan->data = mgr;
+
+	list_add(&mgr->list, &conn->hcon->mgr_list);
+
+	kref_init(&mgr->kref);
+
+	return mgr;
+}
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index 971601e..b3aa4f1 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -42,6 +42,7 @@
 
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
+#include <net/bluetooth/a2mp.h>
 
 static void hci_le_connect(struct hci_conn *conn)
 {
@@ -373,6 +374,8 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)
 
 	INIT_LIST_HEAD(&conn->chan_list);
 
+	INIT_LIST_HEAD(&conn->mgr_list);
+
 	INIT_DELAYED_WORK(&conn->disc_work, hci_conn_timeout);
 	setup_timer(&conn->idle_timer, hci_conn_idle, (unsigned long)conn);
 	setup_timer(&conn->auto_accept_timer, hci_conn_auto_accept,
@@ -393,6 +396,16 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)
 	return conn;
 }
 
+static void hci_amp_mgr_list_flush(struct hci_conn *conn)
+{
+	struct amp_mgr *mgr, *n;
+
+	BT_DBG("conn %p", conn);
+
+	list_for_each_entry_safe(mgr, n, &conn->mgr_list, list)
+		amp_mgr_put(mgr);
+}
+
 int hci_conn_del(struct hci_conn *conn)
 {
 	struct hci_dev *hdev = conn->hdev;
@@ -428,6 +441,8 @@ int hci_conn_del(struct hci_conn *conn)
 
 	hci_chan_list_flush(conn);
 
+	hci_amp_mgr_list_flush(conn);
+
 	hci_conn_hash_del(hdev, conn);
 	if (hdev->notify)
 		hdev->notify(hdev, HCI_NOTIFY_CONN_DEL);
-- 
1.7.9.5


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

* [PATCHv1 03/17] Bluetooth: A2MP: Build and Send msg helpers
  2012-05-18 14:25 [PATCHv1 00/17] Bluetooth A2MP implementation Andrei Emeltchenko
  2012-05-18 14:25 ` [PATCHv1 01/17] Bluetooth: A2MP: Create A2MP channel Andrei Emeltchenko
  2012-05-18 14:25 ` [PATCHv1 02/17] Bluetooth: A2MP: AMP Manager basic functions Andrei Emeltchenko
@ 2012-05-18 14:25 ` Andrei Emeltchenko
  2012-05-18 14:25 ` [PATCHv1 04/17] Bluetooth: A2MP: Add chan callbacks Andrei Emeltchenko
                   ` (17 subsequent siblings)
  20 siblings, 0 replies; 104+ messages in thread
From: Andrei Emeltchenko @ 2012-05-18 14:25 UTC (permalink / raw)
  To: linux-bluetooth

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

Helper function to build and send A2MP messages.

Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
 include/net/bluetooth/a2mp.h |    7 +++++++
 net/bluetooth/a2mp.c         |   46 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 53 insertions(+)

diff --git a/include/net/bluetooth/a2mp.h b/include/net/bluetooth/a2mp.h
index 1c55514..2061e90 100644
--- a/include/net/bluetooth/a2mp.h
+++ b/include/net/bluetooth/a2mp.h
@@ -25,6 +25,13 @@ struct amp_mgr {
 	unsigned long		flags;
 };
 
+struct a2mp_cmd {
+	__u8	code;
+	__u8	ident;
+	__le16	len;
+	__u8	data[0];
+} __packed;
+
 void amp_mgr_get(struct amp_mgr *mgr);
 int amp_mgr_put(struct amp_mgr *mgr);
 
diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c
index 85cd29a..cb3bf74 100644
--- a/net/bluetooth/a2mp.c
+++ b/net/bluetooth/a2mp.c
@@ -17,6 +17,52 @@
 #include <net/bluetooth/l2cap.h>
 #include <net/bluetooth/a2mp.h>
 
+/* A2MP build & send command helper functions */
+static struct a2mp_cmd *__a2mp_build(u8 code, u8 ident, u16 len, void *data)
+{
+	struct a2mp_cmd *cmd;
+	int plen;
+
+	plen = sizeof(*cmd) + len;
+	cmd = kzalloc(plen, GFP_KERNEL);
+	if (!cmd)
+		return NULL;
+
+	cmd->code = code;
+	cmd->ident = ident;
+	cmd->len = cpu_to_le16(len);
+
+	memcpy(cmd->data, data, len);
+
+	return cmd;
+}
+
+static void a2mp_send(struct amp_mgr *mgr, u8 code, u8 ident, u16 len,
+		      void *data)
+{
+	struct l2cap_chan *chan = mgr->a2mp_chan;
+	struct a2mp_cmd *cmd;
+	u16 total_len = len + sizeof(*cmd);
+	struct kvec iv;
+	struct msghdr msg;
+
+	cmd = __a2mp_build(code, ident, len, data);
+	if (!cmd)
+		return;
+
+	iv.iov_base = cmd;
+	iv.iov_len = total_len;
+
+	memset(&msg, 0, sizeof(msg));
+
+	msg.msg_iov = (struct iovec *) &iv;
+	msg.msg_iovlen = 1;
+
+	l2cap_chan_send(chan, &msg, total_len, 0);
+
+	kfree(cmd);
+}
+
 static struct l2cap_ops a2mp_chan_ops = {
 	.name = "L2CAP A2MP channel",
 };
-- 
1.7.9.5


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

* [PATCHv1 04/17] Bluetooth: A2MP: Add chan callbacks
  2012-05-18 14:25 [PATCHv1 00/17] Bluetooth A2MP implementation Andrei Emeltchenko
                   ` (2 preceding siblings ...)
  2012-05-18 14:25 ` [PATCHv1 03/17] Bluetooth: A2MP: Build and Send msg helpers Andrei Emeltchenko
@ 2012-05-18 14:25 ` Andrei Emeltchenko
  2012-05-18 14:25 ` [PATCHv1 05/17] Bluetooth: A2MP: Definitions for A2MP commands Andrei Emeltchenko
                   ` (16 subsequent siblings)
  20 siblings, 0 replies; 104+ messages in thread
From: Andrei Emeltchenko @ 2012-05-18 14:25 UTC (permalink / raw)
  To: linux-bluetooth

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

Add state change, close and skb allocation callbacks.

Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
 net/bluetooth/a2mp.c |   40 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 40 insertions(+)

diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c
index cb3bf74..67a7ad4 100644
--- a/net/bluetooth/a2mp.c
+++ b/net/bluetooth/a2mp.c
@@ -63,8 +63,46 @@ static void a2mp_send(struct amp_mgr *mgr, u8 code, u8 ident, u16 len,
 	kfree(cmd);
 }
 
+static void a2mp_chan_state_change_cb(void *data, int state)
+{
+	struct amp_mgr *mgr = data;
+	struct l2cap_chan *chan;
+
+	if (!mgr)
+		return;
+
+	chan = mgr->a2mp_chan;
+
+	BT_DBG("chan %p state %s", chan, state_to_string(state));
+
+	chan->state = state;
+
+	switch (state) {
+	case BT_CLOSED:
+		if (mgr)
+			amp_mgr_put(mgr);
+		break;
+	}
+}
+
+static void a2mp_chan_close_cb(void *data)
+{
+	struct amp_mgr *mgr = data;
+
+	l2cap_chan_destroy(mgr->a2mp_chan);
+}
+
+static struct sk_buff *a2mp_chan_alloc_skb_cb(struct l2cap_chan *chan,
+					      unsigned long len, int nb)
+{
+	return bt_skb_alloc(len, GFP_KERNEL);
+}
+
 static struct l2cap_ops a2mp_chan_ops = {
 	.name = "L2CAP A2MP channel",
+	.state_change = a2mp_chan_state_change_cb,
+	.close = a2mp_chan_close_cb,
+	.alloc_skb = a2mp_chan_alloc_skb_cb,
 };
 
 static struct l2cap_chan *a2mp_chan_open(struct l2cap_conn *conn)
@@ -102,6 +140,8 @@ static struct l2cap_chan *a2mp_chan_open(struct l2cap_conn *conn)
 	chan->remote_mps = chan->omtu;
 	chan->mps = chan->omtu;
 
+	chan->state = BT_CONNECTED;
+
 	return chan;
 }
 
-- 
1.7.9.5


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

* [PATCHv1 05/17] Bluetooth: A2MP: Definitions for A2MP commands
  2012-05-18 14:25 [PATCHv1 00/17] Bluetooth A2MP implementation Andrei Emeltchenko
                   ` (3 preceding siblings ...)
  2012-05-18 14:25 ` [PATCHv1 04/17] Bluetooth: A2MP: Add chan callbacks Andrei Emeltchenko
@ 2012-05-18 14:25 ` Andrei Emeltchenko
  2012-05-18 14:25 ` [PATCHv1 06/17] Bluetooth: A2MP: Define A2MP status codes Andrei Emeltchenko
                   ` (15 subsequent siblings)
  20 siblings, 0 replies; 104+ messages in thread
From: Andrei Emeltchenko @ 2012-05-18 14:25 UTC (permalink / raw)
  To: linux-bluetooth

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

Define A2MP command IDs and packet structures.

Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
 include/net/bluetooth/a2mp.h |   73 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 73 insertions(+)

diff --git a/include/net/bluetooth/a2mp.h b/include/net/bluetooth/a2mp.h
index 2061e90..52e3a70 100644
--- a/include/net/bluetooth/a2mp.h
+++ b/include/net/bluetooth/a2mp.h
@@ -32,6 +32,79 @@ struct a2mp_cmd {
 	__u8	data[0];
 } __packed;
 
+/* A2MP command codes */
+#define A2MP_COMMAND_REJ         0x01
+struct a2mp_cmd_rej {
+	__le16	reason;
+	__u8	data[0];
+} __packed;
+
+#define A2MP_DISCOVER_REQ        0x02
+struct a2mp_discov_req {
+	__le16	mtu;
+	__le16	ext_feat;
+} __packed;
+
+struct a2mp_cl {
+	__u8	id;
+	__u8	type;
+	__u8	status;
+} __packed;
+
+#define A2MP_DISCOVER_RSP        0x03
+struct a2mp_discov_rsp {
+	__le16     mtu;
+	__le16     ext_feat;
+	struct a2mp_cl cl[0];
+} __packed;
+
+#define A2MP_CHANGE_NOTIFY       0x04
+#define A2MP_CHANGE_RSP          0x05
+
+#define A2MP_GETINFO_REQ         0x06
+struct a2mp_info_req {
+	__u8       id;
+} __packed;
+
+#define A2MP_GETINFO_RSP         0x07
+struct a2mp_info_rsp {
+	__u8	id;
+	__u8	status;
+	__le32	total_bw;
+	__le32	max_bw;
+	__le32	min_latency;
+	__le16	pal_cap;
+	__le16	assoc_size;
+} __packed;
+
+#define A2MP_GETAMPASSOC_REQ     0x08
+struct a2mp_amp_assoc_req {
+	__u8	id;
+} __packed;
+
+#define A2MP_GETAMPASSOC_RSP     0x09
+struct a2mp_amp_assoc_rsp {
+	__u8	id;
+	__u8	status;
+	__u8	amp_assoc[0];
+} __packed;
+
+#define A2MP_CREATEPHYSLINK_REQ  0x0A
+#define A2MP_DISCONNPHYSLINK_REQ 0x0C
+struct a2mp_physlink_req {
+	__u8	local_id;
+	__u8	remote_id;
+	__u8	amp_assoc[0];
+} __packed;
+
+#define A2MP_CREATEPHYSLINK_RSP  0x0B
+#define A2MP_DISCONNPHYSLINK_RSP 0x0D
+struct a2mp_physlink_rsp {
+	__u8	local_id;
+	__u8	remote_id;
+	__u8	status;
+} __packed;
+
 void amp_mgr_get(struct amp_mgr *mgr);
 int amp_mgr_put(struct amp_mgr *mgr);
 
-- 
1.7.9.5


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

* [PATCHv1 06/17] Bluetooth: A2MP: Define A2MP status codes
  2012-05-18 14:25 [PATCHv1 00/17] Bluetooth A2MP implementation Andrei Emeltchenko
                   ` (4 preceding siblings ...)
  2012-05-18 14:25 ` [PATCHv1 05/17] Bluetooth: A2MP: Definitions for A2MP commands Andrei Emeltchenko
@ 2012-05-18 14:25 ` Andrei Emeltchenko
  2012-05-18 14:25 ` [PATCHv1 07/17] Bluetooth: A2MP: Process A2MP messages Andrei Emeltchenko
                   ` (14 subsequent siblings)
  20 siblings, 0 replies; 104+ messages in thread
From: Andrei Emeltchenko @ 2012-05-18 14:25 UTC (permalink / raw)
  To: linux-bluetooth

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

A2MP status codes copied from Bluez patch sent by Peter Krystad
<pkrystad@codeaurora.org>.

Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
 include/net/bluetooth/a2mp.h |   10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/include/net/bluetooth/a2mp.h b/include/net/bluetooth/a2mp.h
index 52e3a70..1f93628 100644
--- a/include/net/bluetooth/a2mp.h
+++ b/include/net/bluetooth/a2mp.h
@@ -105,6 +105,16 @@ struct a2mp_physlink_rsp {
 	__u8	status;
 } __packed;
 
+/* A2MP response status */
+#define A2MP_STATUS_SUCCESS			0x00
+#define A2MP_STATUS_INVALID_CTRL_ID		0x01
+#define A2MP_STATUS_UNABLE_START_LINK_CREATION	0x02
+#define A2MP_STATUS_NO_PHYSICAL_LINK_EXISTS	0x02
+#define A2MP_STATUS_COLLISION_OCCURED		0x03
+#define A2MP_STATUS_DISCONN_REQ_RECVD		0x04
+#define A2MP_STATUS_PHYS_LINK_EXISTS		0x05
+#define A2MP_STATUS_SECURITY_VIOLATION		0x06
+
 void amp_mgr_get(struct amp_mgr *mgr);
 int amp_mgr_put(struct amp_mgr *mgr);
 
-- 
1.7.9.5


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

* [PATCHv1 07/17] Bluetooth: A2MP: Process A2MP messages
  2012-05-18 14:25 [PATCHv1 00/17] Bluetooth A2MP implementation Andrei Emeltchenko
                   ` (5 preceding siblings ...)
  2012-05-18 14:25 ` [PATCHv1 06/17] Bluetooth: A2MP: Define A2MP status codes Andrei Emeltchenko
@ 2012-05-18 14:25 ` Andrei Emeltchenko
  2012-05-18 14:25 ` [PATCHv1 08/17] Bluetooth: A2MP: Process A2MP Command Reject Andrei Emeltchenko
                   ` (13 subsequent siblings)
  20 siblings, 0 replies; 104+ messages in thread
From: Andrei Emeltchenko @ 2012-05-18 14:25 UTC (permalink / raw)
  To: linux-bluetooth

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

Implement basic processing for AMP Manager Protocol (A2MP).

Example below shows processing unrecognized command.
...
> ACL data: handle 11 flags 0x02 dlen 12
    A2MP: code 0x00 ident 3 len 0
< ACL data: handle 11 flags 0x00 dlen 14
    A2MP: Command Reject: reason (0) - Command not recognized
...

Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
 net/bluetooth/a2mp.c |   65 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 65 insertions(+)

diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c
index 67a7ad4..8a2dfbf 100644
--- a/net/bluetooth/a2mp.c
+++ b/net/bluetooth/a2mp.c
@@ -63,6 +63,70 @@ static void a2mp_send(struct amp_mgr *mgr, u8 code, u8 ident, u16 len,
 	kfree(cmd);
 }
 
+/* Handle A2MP signalling */
+static int a2mp_chan_recv_cb(void *data, struct sk_buff *skb)
+{
+	struct a2mp_cmd *hdr = (struct a2mp_cmd *) skb->data;
+	struct amp_mgr *mgr = data;
+	int err = 0;
+
+	amp_mgr_get(mgr);
+
+	while (skb->len >= sizeof(*hdr)) {
+		struct a2mp_cmd *hdr = (struct a2mp_cmd *) skb->data;
+		u16 len = le16_to_cpu(hdr->len);
+
+		BT_DBG("code 0x%02x id %d len %d", hdr->code, hdr->ident, len);
+
+		skb_pull(skb, sizeof(*hdr));
+
+		if (len > skb->len || !hdr->ident) {
+			err = -EINVAL;
+			break;
+		}
+
+		mgr->ident = hdr->ident;
+
+		switch (hdr->code) {
+		case A2MP_COMMAND_REJ:
+		case A2MP_DISCOVER_REQ:
+		case A2MP_CHANGE_NOTIFY:
+		case A2MP_GETINFO_REQ:
+		case A2MP_GETAMPASSOC_REQ:
+		case A2MP_CREATEPHYSLINK_REQ:
+		case A2MP_DISCONNPHYSLINK_REQ:
+		case A2MP_CHANGE_RSP:
+		case A2MP_DISCOVER_RSP:
+		case A2MP_GETINFO_RSP:
+		case A2MP_GETAMPASSOC_RSP:
+		case A2MP_CREATEPHYSLINK_RSP:
+		case A2MP_DISCONNPHYSLINK_RSP:
+		default:
+			BT_ERR("Unknown A2MP sig cmd 0x%2.2x", hdr->code);
+			err = -EINVAL;
+			break;
+		}
+	}
+
+	if (err) {
+		struct a2mp_cmd_rej rej;
+		rej.reason = cpu_to_le16(0);
+
+		BT_DBG("Send A2MP Rej: cmd 0x%2.2x err %d", hdr->code, err);
+
+		a2mp_send(mgr, A2MP_COMMAND_REJ, hdr->ident, sizeof(rej),
+			  &rej);
+	}
+
+	/* Always free skb and return success error code to prevent
+	   from sending L2CAP Disconnect over A2MP channel */
+	kfree_skb(skb);
+
+	amp_mgr_put(mgr);
+
+	return 0;
+}
+
 static void a2mp_chan_state_change_cb(void *data, int state)
 {
 	struct amp_mgr *mgr = data;
@@ -100,6 +164,7 @@ static struct sk_buff *a2mp_chan_alloc_skb_cb(struct l2cap_chan *chan,
 
 static struct l2cap_ops a2mp_chan_ops = {
 	.name = "L2CAP A2MP channel",
+	.recv = a2mp_chan_recv_cb,
 	.state_change = a2mp_chan_state_change_cb,
 	.close = a2mp_chan_close_cb,
 	.alloc_skb = a2mp_chan_alloc_skb_cb,
-- 
1.7.9.5


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

* [PATCHv1 08/17] Bluetooth: A2MP: Process A2MP Command Reject
  2012-05-18 14:25 [PATCHv1 00/17] Bluetooth A2MP implementation Andrei Emeltchenko
                   ` (6 preceding siblings ...)
  2012-05-18 14:25 ` [PATCHv1 07/17] Bluetooth: A2MP: Process A2MP messages Andrei Emeltchenko
@ 2012-05-18 14:25 ` Andrei Emeltchenko
  2012-05-18 14:25 ` [PATCHv1 09/17] Bluetooth: A2MP: Process A2MP Discover Request Andrei Emeltchenko
                   ` (12 subsequent siblings)
  20 siblings, 0 replies; 104+ messages in thread
From: Andrei Emeltchenko @ 2012-05-18 14:25 UTC (permalink / raw)
  To: linux-bluetooth

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

Placeholder for future A2MP Command Reject handler.

Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
 net/bluetooth/a2mp.c |   19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c
index 8a2dfbf..a104f7a 100644
--- a/net/bluetooth/a2mp.c
+++ b/net/bluetooth/a2mp.c
@@ -63,6 +63,22 @@ static void a2mp_send(struct amp_mgr *mgr, u8 code, u8 ident, u16 len,
 	kfree(cmd);
 }
 
+/* Processing A2MP messages */
+static int a2mp_command_rej(struct amp_mgr *mgr, struct sk_buff *skb,
+			    struct a2mp_cmd *hdr)
+{
+	struct a2mp_cmd_rej *rej = (struct a2mp_cmd_rej *) skb->data;
+
+	if (le16_to_cpu(hdr->len) < sizeof(*rej))
+		return -EINVAL;
+
+	BT_DBG("ident %d reason %d", hdr->ident, le16_to_cpu(rej->reason));
+
+	skb_pull(skb, sizeof(*rej));
+
+	return 0;
+}
+
 /* Handle A2MP signalling */
 static int a2mp_chan_recv_cb(void *data, struct sk_buff *skb)
 {
@@ -89,6 +105,9 @@ static int a2mp_chan_recv_cb(void *data, struct sk_buff *skb)
 
 		switch (hdr->code) {
 		case A2MP_COMMAND_REJ:
+			a2mp_command_rej(mgr, skb, hdr);
+			break;
+
 		case A2MP_DISCOVER_REQ:
 		case A2MP_CHANGE_NOTIFY:
 		case A2MP_GETINFO_REQ:
-- 
1.7.9.5


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

* [PATCHv1 09/17] Bluetooth: A2MP: Process A2MP Discover Request
  2012-05-18 14:25 [PATCHv1 00/17] Bluetooth A2MP implementation Andrei Emeltchenko
                   ` (7 preceding siblings ...)
  2012-05-18 14:25 ` [PATCHv1 08/17] Bluetooth: A2MP: Process A2MP Command Reject Andrei Emeltchenko
@ 2012-05-18 14:25 ` Andrei Emeltchenko
  2012-05-18 14:25 ` [PATCHv1 10/17] Bluetooth: A2MP: Process A2MP Change Notify Andrei Emeltchenko
                   ` (11 subsequent siblings)
  20 siblings, 0 replies; 104+ messages in thread
From: Andrei Emeltchenko @ 2012-05-18 14:25 UTC (permalink / raw)
  To: linux-bluetooth

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

Adds helper functions to count HCI devs and process A2MP Discover
Request, code makes sure that first controller in the list is
BREDR one. Trace is shown below:

...
> ACL data: handle 11 flags 0x02 dlen 16
    A2MP: Discover req: mtu/mps 670 mask: 0x0000
< ACL data: handle 11 flags 0x00 dlen 22
    A2MP: Discover rsp: mtu/mps 670 mask: 0x0000
      Controller list:
        id 0 type 0 (BR-EDR) status 0x01 (Bluetooth only)
        id 1 type 1 (802.11 AMP) status 0x01 (Bluetooth only)
...

Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
 include/net/bluetooth/a2mp.h     |    2 +
 include/net/bluetooth/hci_core.h |   13 ++++++
 net/bluetooth/a2mp.c             |   85 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 100 insertions(+)

diff --git a/include/net/bluetooth/a2mp.h b/include/net/bluetooth/a2mp.h
index 1f93628..980c266 100644
--- a/include/net/bluetooth/a2mp.h
+++ b/include/net/bluetooth/a2mp.h
@@ -15,6 +15,8 @@
 #ifndef __A2MP_H
 #define __A2MP_H
 
+#define A2MP_FEAT_EXT	0x8000
+
 struct amp_mgr {
 	struct list_head	list;
 	struct l2cap_conn	*l2cap_conn;
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 3d9b07f..612b93e 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -641,6 +641,19 @@ static inline void hci_set_drvdata(struct hci_dev *hdev, void *data)
 	dev_set_drvdata(&hdev->dev, data);
 }
 
+/* hci_dev_list shall be locked */
+static inline uint8_t __hci_num_ctrl(void)
+{
+	uint8_t count = 0;
+	struct list_head *p;
+
+	list_for_each(p, &hci_dev_list) {
+		count++;
+	}
+
+	return count;
+}
+
 struct hci_dev *hci_dev_get(int index);
 struct hci_dev *hci_get_route(bdaddr_t *src, bdaddr_t *dst);
 
diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c
index a104f7a..ab6ef31 100644
--- a/net/bluetooth/a2mp.c
+++ b/net/bluetooth/a2mp.c
@@ -63,6 +63,36 @@ static void a2mp_send(struct amp_mgr *mgr, u8 code, u8 ident, u16 len,
 	kfree(cmd);
 }
 
+static inline void __a2mp_cl_bredr(struct a2mp_cl *cl)
+{
+	cl->id = 0;
+	cl->type = 0;
+	cl->status = 1;
+}
+
+/* hci_dev_list shall be locked */
+static void __a2mp_add_cl(struct amp_mgr *mgr, struct a2mp_cl *cl, u8 num_ctrl)
+{
+	int i = 0;
+	struct hci_dev *hdev;
+
+	__a2mp_cl_bredr(cl);
+
+	list_for_each_entry(hdev, &hci_dev_list, list) {
+		/* Iterate through AMP controllers */
+		if (hdev->id == HCI_BREDR_ID)
+			continue;
+
+		/* Starting from second entry */
+		if (++i >= num_ctrl)
+			return;
+
+		cl[i].id = hdev->id;
+		cl[i].type = hdev->amp_type;
+		cl[i].status = hdev->amp_status;
+	}
+}
+
 /* Processing A2MP messages */
 static int a2mp_command_rej(struct amp_mgr *mgr, struct sk_buff *skb,
 			    struct a2mp_cmd *hdr)
@@ -79,6 +109,58 @@ static int a2mp_command_rej(struct amp_mgr *mgr, struct sk_buff *skb,
 	return 0;
 }
 
+static int a2mp_discover_req(struct amp_mgr *mgr, struct sk_buff *skb,
+			     struct a2mp_cmd *hdr)
+{
+	struct a2mp_discov_req *req = (struct a2mp_discov_req *) skb->data;
+	u16 len = le16_to_cpu(hdr->len);
+	struct a2mp_discov_rsp *rsp;
+	u16 ext_feat;
+	u8 num_ctrl;
+
+	if (len < sizeof(*req))
+		return -EINVAL;
+
+	skb_pull(skb, sizeof(*req));
+
+	ext_feat = le16_to_cpu(req->ext_feat);
+
+	BT_DBG("mtu %d efm 0x%4.4x", le16_to_cpu(req->mtu), ext_feat);
+
+	/* check that packet is not broken for now */
+	while (ext_feat & A2MP_FEAT_EXT) {
+		if (len < sizeof(ext_feat))
+			return -EINVAL;
+
+		ext_feat = get_unaligned_le16(skb->data);
+		BT_DBG("efm 0x%4.4x", ext_feat);
+		len -= sizeof(ext_feat);
+		skb_pull(skb, sizeof(ext_feat));
+	}
+
+	read_lock(&hci_dev_list_lock);
+
+	num_ctrl = __hci_num_ctrl();
+	len = num_ctrl * sizeof(struct a2mp_cl) + sizeof(*rsp);
+	rsp = kmalloc(len, GFP_ATOMIC);
+	if (!rsp) {
+		read_unlock(&hci_dev_list_lock);
+		return -ENOMEM;
+	}
+
+	rsp->mtu = cpu_to_le16(L2CAP_A2MP_DEFAULT_MTU);
+	rsp->ext_feat = 0;
+
+	__a2mp_add_cl(mgr, rsp->cl, num_ctrl);
+
+	read_unlock(&hci_dev_list_lock);
+
+	a2mp_send(mgr, A2MP_DISCOVER_RSP, hdr->ident, len, rsp);
+
+	kfree(rsp);
+	return 0;
+}
+
 /* Handle A2MP signalling */
 static int a2mp_chan_recv_cb(void *data, struct sk_buff *skb)
 {
@@ -109,6 +191,9 @@ static int a2mp_chan_recv_cb(void *data, struct sk_buff *skb)
 			break;
 
 		case A2MP_DISCOVER_REQ:
+			err = a2mp_discover_req(mgr, skb, hdr);
+			break;
+
 		case A2MP_CHANGE_NOTIFY:
 		case A2MP_GETINFO_REQ:
 		case A2MP_GETAMPASSOC_REQ:
-- 
1.7.9.5


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

* [PATCHv1 10/17] Bluetooth: A2MP: Process A2MP Change Notify
  2012-05-18 14:25 [PATCHv1 00/17] Bluetooth A2MP implementation Andrei Emeltchenko
                   ` (8 preceding siblings ...)
  2012-05-18 14:25 ` [PATCHv1 09/17] Bluetooth: A2MP: Process A2MP Discover Request Andrei Emeltchenko
@ 2012-05-18 14:25 ` Andrei Emeltchenko
  2012-05-18 14:25 ` [PATCHv1 11/17] Bluetooth: A2MP: Process A2MP Get Info Request Andrei Emeltchenko
                   ` (10 subsequent siblings)
  20 siblings, 0 replies; 104+ messages in thread
From: Andrei Emeltchenko @ 2012-05-18 14:25 UTC (permalink / raw)
  To: linux-bluetooth

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

Placeholder for A2MP Change Notify handler.

Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
 net/bluetooth/a2mp.c |   19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c
index ab6ef31..77efb7d 100644
--- a/net/bluetooth/a2mp.c
+++ b/net/bluetooth/a2mp.c
@@ -161,6 +161,22 @@ static int a2mp_discover_req(struct amp_mgr *mgr, struct sk_buff *skb,
 	return 0;
 }
 
+static int a2mp_change_notify(struct amp_mgr *mgr, struct sk_buff *skb,
+			      struct a2mp_cmd *hdr)
+{
+	struct a2mp_cl *cl = (struct a2mp_cl *) skb->data;
+
+	while (skb->len >= sizeof(*cl)) {
+		BT_DBG("Controller id %d type %d status %d", cl->id, cl->type,
+		       cl->status);
+		cl = (struct a2mp_cl *) skb_pull(skb, sizeof(*cl));
+	}
+
+	/* TODO send A2MP_CHANGE_RSP */
+
+	return 0;
+}
+
 /* Handle A2MP signalling */
 static int a2mp_chan_recv_cb(void *data, struct sk_buff *skb)
 {
@@ -195,6 +211,9 @@ static int a2mp_chan_recv_cb(void *data, struct sk_buff *skb)
 			break;
 
 		case A2MP_CHANGE_NOTIFY:
+			err = a2mp_change_notify(mgr, skb, hdr);
+			break;
+
 		case A2MP_GETINFO_REQ:
 		case A2MP_GETAMPASSOC_REQ:
 		case A2MP_CREATEPHYSLINK_REQ:
-- 
1.7.9.5


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

* [PATCHv1 11/17] Bluetooth: A2MP: Process A2MP Get Info Request
  2012-05-18 14:25 [PATCHv1 00/17] Bluetooth A2MP implementation Andrei Emeltchenko
                   ` (9 preceding siblings ...)
  2012-05-18 14:25 ` [PATCHv1 10/17] Bluetooth: A2MP: Process A2MP Change Notify Andrei Emeltchenko
@ 2012-05-18 14:25 ` Andrei Emeltchenko
  2012-05-18 14:25 ` [PATCHv1 12/17] Bluetooth: A2MP: Process A2MP Get AMP Assoc Request Andrei Emeltchenko
                   ` (9 subsequent siblings)
  20 siblings, 0 replies; 104+ messages in thread
From: Andrei Emeltchenko @ 2012-05-18 14:25 UTC (permalink / raw)
  To: linux-bluetooth

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

Process A2MP Get Info Request.
Example of trace log for invalid controller id is shown below:

...
> ACL data: handle 11 flags 0x02 dlen 13
    A2MP: Get Info req: id 238
< ACL data: handle 11 flags 0x00 dlen 30
    A2MP: Get Info rsp: id 238 status (1) Invalid Controller ID
...

Note that If the Status field is set to Invalid Controller ID all subsequent
fields in the AMP Get Info Response shall be ignored by the receiver.

Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
 net/bluetooth/a2mp.c |   37 +++++++++++++++++++++++++++++++++++++
 1 file changed, 37 insertions(+)

diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c
index 77efb7d..e48e7f3 100644
--- a/net/bluetooth/a2mp.c
+++ b/net/bluetooth/a2mp.c
@@ -177,6 +177,40 @@ static int a2mp_change_notify(struct amp_mgr *mgr, struct sk_buff *skb,
 	return 0;
 }
 
+static int a2mp_getinfo_req(struct amp_mgr *mgr, struct sk_buff *skb,
+			    struct a2mp_cmd *hdr)
+{
+	struct a2mp_info_req *req  = (struct a2mp_info_req *) skb->data;
+	struct a2mp_info_rsp rsp;
+	struct hci_dev *hdev;
+
+	if (le16_to_cpu(hdr->len) < sizeof(*req))
+		return -EINVAL;
+
+	BT_DBG("id %d", req->id);
+
+	rsp.id = req->id;
+	rsp.status = A2MP_STATUS_INVALID_CTRL_ID;
+
+	hdev = hci_dev_get(req->id);
+	if (hdev && hdev->amp_type != HCI_BREDR) {
+		rsp.status = 0;
+		rsp.total_bw = cpu_to_le32(hdev->amp_total_bw);
+		rsp.max_bw = cpu_to_le32(hdev->amp_max_bw);
+		rsp.min_latency = cpu_to_le32(hdev->amp_min_latency);
+		rsp.pal_cap = cpu_to_le16(hdev->amp_pal_cap);
+		rsp.assoc_size = cpu_to_le16(hdev->amp_assoc_size);
+	}
+
+	if (hdev)
+		hci_dev_put(hdev);
+
+	a2mp_send(mgr, A2MP_GETINFO_RSP, hdr->ident, sizeof(rsp), &rsp);
+
+	skb_pull(skb, sizeof(*req));
+	return 0;
+}
+
 /* Handle A2MP signalling */
 static int a2mp_chan_recv_cb(void *data, struct sk_buff *skb)
 {
@@ -215,6 +249,9 @@ static int a2mp_chan_recv_cb(void *data, struct sk_buff *skb)
 			break;
 
 		case A2MP_GETINFO_REQ:
+			err = a2mp_getinfo_req(mgr, skb, hdr);
+			break;
+
 		case A2MP_GETAMPASSOC_REQ:
 		case A2MP_CREATEPHYSLINK_REQ:
 		case A2MP_DISCONNPHYSLINK_REQ:
-- 
1.7.9.5


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

* [PATCHv1 12/17] Bluetooth: A2MP: Process A2MP Get AMP Assoc Request
  2012-05-18 14:25 [PATCHv1 00/17] Bluetooth A2MP implementation Andrei Emeltchenko
                   ` (10 preceding siblings ...)
  2012-05-18 14:25 ` [PATCHv1 11/17] Bluetooth: A2MP: Process A2MP Get Info Request Andrei Emeltchenko
@ 2012-05-18 14:25 ` Andrei Emeltchenko
  2012-05-18 14:25 ` [PATCHv1 13/17] Bluetooth: A2MP: Process A2MP Create Physlink Request Andrei Emeltchenko
                   ` (8 subsequent siblings)
  20 siblings, 0 replies; 104+ messages in thread
From: Andrei Emeltchenko @ 2012-05-18 14:25 UTC (permalink / raw)
  To: linux-bluetooth

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

Example trace when receiving AMP Assoc Request with wrong AMP id.
...
> ACL data: handle 11 flags 0x02 dlen 13
    A2MP: Get AMP Assoc req: id 238
< ACL data: handle 11 flags 0x00 dlen 14
    A2MP: Get AMP Assoc rsp: id 238 status (1) Invalid Controller ID
      assoc data:
...

Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
 net/bluetooth/a2mp.c |   36 ++++++++++++++++++++++++++++++++++++
 1 file changed, 36 insertions(+)

diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c
index e48e7f3..5498d67 100644
--- a/net/bluetooth/a2mp.c
+++ b/net/bluetooth/a2mp.c
@@ -211,6 +211,39 @@ static int a2mp_getinfo_req(struct amp_mgr *mgr, struct sk_buff *skb,
 	return 0;
 }
 
+static int a2mp_getampassoc_req(struct amp_mgr *mgr, struct sk_buff *skb,
+				struct a2mp_cmd *hdr)
+{
+	struct a2mp_amp_assoc_req *req =
+				(struct a2mp_amp_assoc_req *) skb->data;
+	struct hci_dev *hdev;
+
+	if (le16_to_cpu(hdr->len) < sizeof(*req))
+		return -EINVAL;
+
+	BT_DBG("id %d", req->id);
+
+	hdev = hci_dev_get(req->id);
+	if (!hdev || hdev->amp_type == HCI_BREDR) {
+		struct a2mp_amp_assoc_rsp rsp;
+		rsp.id = req->id;
+		rsp.status = A2MP_STATUS_INVALID_CTRL_ID;
+
+		a2mp_send(mgr, A2MP_GETAMPASSOC_RSP, hdr->ident, sizeof(rsp),
+			  &rsp);
+		goto clean;
+	}
+
+	/* Placeholder for HCI Read AMP Assoc */
+
+clean:
+	if (hdev)
+		hci_dev_put(hdev);
+
+	skb_pull(skb, sizeof(*req));
+	return 0;
+}
+
 /* Handle A2MP signalling */
 static int a2mp_chan_recv_cb(void *data, struct sk_buff *skb)
 {
@@ -253,6 +286,9 @@ static int a2mp_chan_recv_cb(void *data, struct sk_buff *skb)
 			break;
 
 		case A2MP_GETAMPASSOC_REQ:
+			err = a2mp_getampassoc_req(mgr, skb, hdr);
+			break;
+
 		case A2MP_CREATEPHYSLINK_REQ:
 		case A2MP_DISCONNPHYSLINK_REQ:
 		case A2MP_CHANGE_RSP:
-- 
1.7.9.5


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

* [PATCHv1 13/17] Bluetooth: A2MP: Process A2MP Create Physlink Request
  2012-05-18 14:25 [PATCHv1 00/17] Bluetooth A2MP implementation Andrei Emeltchenko
                   ` (11 preceding siblings ...)
  2012-05-18 14:25 ` [PATCHv1 12/17] Bluetooth: A2MP: Process A2MP Get AMP Assoc Request Andrei Emeltchenko
@ 2012-05-18 14:25 ` Andrei Emeltchenko
  2012-05-18 14:25 ` [PATCHv1 14/17] Bluetooth: A2MP: Process A2MP Disc " Andrei Emeltchenko
                   ` (7 subsequent siblings)
  20 siblings, 0 replies; 104+ messages in thread
From: Andrei Emeltchenko @ 2012-05-18 14:25 UTC (permalink / raw)
  To: linux-bluetooth

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

Placeholder for A2MP Create Physlink Request.
Handles requests with invalid controler id as shown below:

...
> ACL data: handle 11 flags 0x02 dlen 50
    A2MP: Create Physical Link req: local id 1 remote id 85
      Assoc data:
        <skipped>
< ACL data: handle 11 flags 0x00 dlen 15
    A2MP: Create Physical Link rsp: local id 85 remote id 1 status 1
      Invalid Controller ID
...

Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
 net/bluetooth/a2mp.c |   39 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 39 insertions(+)

diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c
index 5498d67..ca37116 100644
--- a/net/bluetooth/a2mp.c
+++ b/net/bluetooth/a2mp.c
@@ -244,6 +244,42 @@ clean:
 	return 0;
 }
 
+static int a2mp_createphyslink_req(struct amp_mgr *mgr, struct sk_buff *skb,
+				   struct a2mp_cmd *hdr)
+{
+	struct a2mp_physlink_req *req = (struct a2mp_physlink_req *) skb->data;
+	struct a2mp_physlink_rsp rsp;
+	struct hci_dev *hdev;
+
+	if (le16_to_cpu(hdr->len) < sizeof(*req))
+		return -EINVAL;
+
+	BT_DBG("local_id %d, remote_id %d", req->local_id, req->remote_id);
+
+	rsp.local_id = req->remote_id;
+	rsp.remote_id = req->local_id;
+
+	hdev = hci_dev_get(req->remote_id);
+	if (!hdev || hdev->amp_type != HCI_AMP) {
+		rsp.status = A2MP_STATUS_INVALID_CTRL_ID;
+		goto send_rsp;
+	}
+
+	/* TODO process physlink create */
+
+	rsp.status = A2MP_STATUS_SUCCESS;
+
+send_rsp:
+	if (hdev)
+		hci_dev_put(hdev);
+
+	a2mp_send(mgr, A2MP_CREATEPHYSLINK_RSP, hdr->ident, sizeof(rsp),
+		  &rsp);
+
+	skb_pull(skb, le16_to_cpu(hdr->len));
+	return 0;
+}
+
 /* Handle A2MP signalling */
 static int a2mp_chan_recv_cb(void *data, struct sk_buff *skb)
 {
@@ -290,6 +326,9 @@ static int a2mp_chan_recv_cb(void *data, struct sk_buff *skb)
 			break;
 
 		case A2MP_CREATEPHYSLINK_REQ:
+			err = a2mp_createphyslink_req(mgr, skb, hdr);
+			break;
+
 		case A2MP_DISCONNPHYSLINK_REQ:
 		case A2MP_CHANGE_RSP:
 		case A2MP_DISCOVER_RSP:
-- 
1.7.9.5


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

* [PATCHv1 14/17] Bluetooth: A2MP: Process A2MP Disc Physlink Request
  2012-05-18 14:25 [PATCHv1 00/17] Bluetooth A2MP implementation Andrei Emeltchenko
                   ` (12 preceding siblings ...)
  2012-05-18 14:25 ` [PATCHv1 13/17] Bluetooth: A2MP: Process A2MP Create Physlink Request Andrei Emeltchenko
@ 2012-05-18 14:25 ` Andrei Emeltchenko
  2012-05-18 14:25 ` [PATCHv1 15/17] Bluetooth: A2MP: Process A2MP Command Responses Andrei Emeltchenko
                   ` (6 subsequent siblings)
  20 siblings, 0 replies; 104+ messages in thread
From: Andrei Emeltchenko @ 2012-05-18 14:25 UTC (permalink / raw)
  To: linux-bluetooth

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

Placeholder for A2MP Disconnect Physlink Request.

Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
 net/bluetooth/a2mp.c |   36 ++++++++++++++++++++++++++++++++++++
 1 file changed, 36 insertions(+)

diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c
index ca37116..69deec0 100644
--- a/net/bluetooth/a2mp.c
+++ b/net/bluetooth/a2mp.c
@@ -280,6 +280,39 @@ send_rsp:
 	return 0;
 }
 
+static int a2mp_discphyslink_req(struct amp_mgr *mgr, struct sk_buff *skb,
+				 struct a2mp_cmd *hdr)
+{
+	struct a2mp_physlink_req *req = (struct a2mp_physlink_req *) skb->data;
+	struct a2mp_physlink_rsp rsp;
+	struct hci_dev *hdev;
+
+	if (le16_to_cpu(hdr->len) < sizeof(*req))
+		return -EINVAL;
+
+	BT_DBG("local_id %d remote_id %d", req->local_id, req->remote_id);
+
+	rsp.local_id = req->remote_id;
+	rsp.remote_id = req->local_id;
+	rsp.status = A2MP_STATUS_SUCCESS;
+
+	hdev = hci_dev_get(req->local_id);
+	if (!hdev) {
+		rsp.status = A2MP_STATUS_INVALID_CTRL_ID;
+		goto send_rsp;
+	}
+
+	/* TODO Disconnect Phys Link here */
+
+	hci_dev_put(hdev);
+
+send_rsp:
+	a2mp_send(mgr, A2MP_DISCONNPHYSLINK_RSP, hdr->ident, sizeof(rsp), &rsp);
+
+	skb_pull(skb, sizeof(*req));
+	return 0;
+}
+
 /* Handle A2MP signalling */
 static int a2mp_chan_recv_cb(void *data, struct sk_buff *skb)
 {
@@ -330,6 +363,9 @@ static int a2mp_chan_recv_cb(void *data, struct sk_buff *skb)
 			break;
 
 		case A2MP_DISCONNPHYSLINK_REQ:
+			err = a2mp_discphyslink_req(mgr, skb, hdr);
+			break;
+
 		case A2MP_CHANGE_RSP:
 		case A2MP_DISCOVER_RSP:
 		case A2MP_GETINFO_RSP:
-- 
1.7.9.5


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

* [PATCHv1 15/17] Bluetooth: A2MP: Process A2MP Command Responses
  2012-05-18 14:25 [PATCHv1 00/17] Bluetooth A2MP implementation Andrei Emeltchenko
                   ` (13 preceding siblings ...)
  2012-05-18 14:25 ` [PATCHv1 14/17] Bluetooth: A2MP: Process A2MP Disc " Andrei Emeltchenko
@ 2012-05-18 14:25 ` Andrei Emeltchenko
  2012-05-18 14:25 ` [PATCHv1 16/17] Bluetooth: A2MP: Handling fixed channels Andrei Emeltchenko
                   ` (5 subsequent siblings)
  20 siblings, 0 replies; 104+ messages in thread
From: Andrei Emeltchenko @ 2012-05-18 14:25 UTC (permalink / raw)
  To: linux-bluetooth

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

Process A2MP responses, print cmd code and ident for now.

Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
 net/bluetooth/a2mp.c |   12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c
index 69deec0..4616da1 100644
--- a/net/bluetooth/a2mp.c
+++ b/net/bluetooth/a2mp.c
@@ -313,6 +313,15 @@ send_rsp:
 	return 0;
 }
 
+static inline int a2mp_cmd_rsp(struct amp_mgr *mgr, struct sk_buff *skb,
+			       struct a2mp_cmd *hdr)
+{
+	BT_DBG("ident %d code %d", hdr->ident, hdr->code);
+
+	skb_pull(skb, le16_to_cpu(hdr->len));
+	return 0;
+}
+
 /* Handle A2MP signalling */
 static int a2mp_chan_recv_cb(void *data, struct sk_buff *skb)
 {
@@ -372,6 +381,9 @@ static int a2mp_chan_recv_cb(void *data, struct sk_buff *skb)
 		case A2MP_GETAMPASSOC_RSP:
 		case A2MP_CREATEPHYSLINK_RSP:
 		case A2MP_DISCONNPHYSLINK_RSP:
+			err = a2mp_cmd_rsp(mgr, skb, hdr);
+			break;
+
 		default:
 			BT_ERR("Unknown A2MP sig cmd 0x%2.2x", hdr->code);
 			err = -EINVAL;
-- 
1.7.9.5


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

* [PATCHv1 16/17] Bluetooth: A2MP: Handling fixed channels
  2012-05-18 14:25 [PATCHv1 00/17] Bluetooth A2MP implementation Andrei Emeltchenko
                   ` (14 preceding siblings ...)
  2012-05-18 14:25 ` [PATCHv1 15/17] Bluetooth: A2MP: Process A2MP Command Responses Andrei Emeltchenko
@ 2012-05-18 14:25 ` Andrei Emeltchenko
  2012-05-21 22:28   ` Mat Martineau
  2012-05-18 14:25 ` [PATCHv1 17/17] Bluetooth: A2MP: Manage incoming connections Andrei Emeltchenko
                   ` (4 subsequent siblings)
  20 siblings, 1 reply; 104+ messages in thread
From: Andrei Emeltchenko @ 2012-05-18 14:25 UTC (permalink / raw)
  To: linux-bluetooth

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

A2MP fixed channel do not have sk

Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
 include/net/bluetooth/l2cap.h |    1 +
 net/bluetooth/a2mp.c          |    3 +--
 net/bluetooth/l2cap_core.c    |   25 +++++++++++++++++++++++--
 3 files changed, 25 insertions(+), 4 deletions(-)

diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index 8cc739f..db47103 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -582,6 +582,7 @@ struct l2cap_conn {
 #define L2CAP_CHAN_RAW			1
 #define L2CAP_CHAN_CONN_LESS		2
 #define L2CAP_CHAN_CONN_ORIENTED	3
+#define L2CAP_CHAN_CONN_FIX_A2MP	4
 
 /* ----- L2CAP socket info ----- */
 #define l2cap_pi(sk) ((struct l2cap_pinfo *) sk)
diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c
index 4616da1..86b2078 100644
--- a/net/bluetooth/a2mp.c
+++ b/net/bluetooth/a2mp.c
@@ -465,8 +465,7 @@ static struct l2cap_chan *a2mp_chan_open(struct l2cap_conn *conn)
 
 	hci_conn_hold(conn->hcon);
 
-	chan->omtu = L2CAP_A2MP_DEFAULT_MTU;
-	chan->imtu = L2CAP_A2MP_DEFAULT_MTU;
+	chan->chan_type = L2CAP_CHAN_CONN_FIX_A2MP;
 	chan->flush_to = L2CAP_DEFAULT_FLUSH_TO;
 
 	chan->ops = &a2mp_chan_ops;
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index ee333f0..b5c4229 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -450,6 +450,13 @@ static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
 		chan->omtu = L2CAP_DEFAULT_MTU;
 		break;
 
+	case L2CAP_CHAN_CONN_FIX_A2MP:
+		chan->scid = L2CAP_CID_A2MP;
+		chan->dcid = L2CAP_CID_A2MP;
+		chan->omtu = L2CAP_A2MP_DEFAULT_MTU;
+		chan->imtu = L2CAP_A2MP_DEFAULT_MTU;
+		break;
+
 	default:
 		/* Raw socket can send/recv signalling messages only */
 		chan->scid = L2CAP_CID_SIGNALING;
@@ -480,7 +487,7 @@ static void l2cap_chan_del(struct l2cap_chan *chan, int err)
 {
 	struct sock *sk = chan->sk;
 	struct l2cap_conn *conn = chan->conn;
-	struct sock *parent = bt_sk(sk)->parent;
+	struct sock *parent;
 
 	__clear_chan_timer(chan);
 
@@ -496,6 +503,9 @@ static void l2cap_chan_del(struct l2cap_chan *chan, int err)
 		hci_conn_put(conn->hcon);
 	}
 
+	if (chan->chan_type == L2CAP_CHAN_CONN_FIX_A2MP)
+		goto clean;
+
 	lock_sock(sk);
 
 	__l2cap_state_change(chan, BT_CLOSED);
@@ -504,6 +514,7 @@ static void l2cap_chan_del(struct l2cap_chan *chan, int err)
 	if (err)
 		__l2cap_chan_set_err(chan, err);
 
+	parent = bt_sk(sk)->parent;
 	if (parent) {
 		bt_accept_unlink(sk);
 		parent->sk_data_ready(parent, 0);
@@ -515,6 +526,7 @@ static void l2cap_chan_del(struct l2cap_chan *chan, int err)
 	if (test_bit(CONF_NOT_COMPLETE, &chan->conf_state))
 		return;
 
+clean:
 	skb_queue_purge(&chan->tx_q);
 
 	if (chan->mode == L2CAP_MODE_ERTM) {
@@ -992,6 +1004,9 @@ static void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *c
 	if (!conn)
 		return;
 
+	if (chan->chan_type == L2CAP_CHAN_CONN_FIX_A2MP)
+		return;
+
 	if (chan->mode == L2CAP_MODE_ERTM) {
 		__clear_retrans_timer(chan);
 		__clear_monitor_timer(chan);
@@ -1201,6 +1216,11 @@ static void l2cap_conn_ready(struct l2cap_conn *conn)
 
 		l2cap_chan_lock(chan);
 
+		if (chan->chan_type == L2CAP_CHAN_CONN_FIX_A2MP) {
+			l2cap_chan_unlock(chan);
+			continue;
+		}
+
 		if (conn->hcon->type == LE_LINK) {
 			if (smp_conn_security(conn, chan->sec_level))
 				l2cap_chan_ready(chan);
@@ -1581,7 +1601,8 @@ static void l2cap_monitor_timeout(struct work_struct *work)
 	l2cap_chan_lock(chan);
 
 	if (chan->retry_count >= chan->remote_max_tx) {
-		l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
+		if (chan->chan_type != L2CAP_CHAN_CONN_FIX_A2MP)
+			l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
 		l2cap_chan_unlock(chan);
 		l2cap_chan_put(chan);
 		return;
-- 
1.7.9.5


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

* [PATCHv1 17/17] Bluetooth: A2MP: Manage incoming connections
  2012-05-18 14:25 [PATCHv1 00/17] Bluetooth A2MP implementation Andrei Emeltchenko
                   ` (15 preceding siblings ...)
  2012-05-18 14:25 ` [PATCHv1 16/17] Bluetooth: A2MP: Handling fixed channels Andrei Emeltchenko
@ 2012-05-18 14:25 ` Andrei Emeltchenko
  2012-05-21 22:45   ` Mat Martineau
  2012-05-18 20:57 ` [PATCHv1 00/17] Bluetooth A2MP implementation Gustavo Padovan
                   ` (3 subsequent siblings)
  20 siblings, 1 reply; 104+ messages in thread
From: Andrei Emeltchenko @ 2012-05-18 14:25 UTC (permalink / raw)
  To: linux-bluetooth

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

Handle incoming A2MP connection by creating AMP manager and
processing A2MP messages.

Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
 include/net/bluetooth/a2mp.h |    4 ++++
 net/bluetooth/a2mp.c         |   12 ++++++++++++
 net/bluetooth/l2cap_core.c   |   14 ++++++++++----
 3 files changed, 26 insertions(+), 4 deletions(-)

diff --git a/include/net/bluetooth/a2mp.h b/include/net/bluetooth/a2mp.h
index 980c266..b4f74c6 100644
--- a/include/net/bluetooth/a2mp.h
+++ b/include/net/bluetooth/a2mp.h
@@ -15,6 +15,8 @@
 #ifndef __A2MP_H
 #define __A2MP_H
 
+#include <net/bluetooth/l2cap.h>
+
 #define A2MP_FEAT_EXT	0x8000
 
 struct amp_mgr {
@@ -119,5 +121,7 @@ struct a2mp_physlink_rsp {
 
 void amp_mgr_get(struct amp_mgr *mgr);
 int amp_mgr_put(struct amp_mgr *mgr);
+struct l2cap_chan *a2mp_channel_create(struct l2cap_conn *conn,
+				       struct sk_buff *skb);
 
 #endif /* __A2MP_H */
diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c
index 86b2078..dda297d 100644
--- a/net/bluetooth/a2mp.c
+++ b/net/bluetooth/a2mp.c
@@ -544,3 +544,15 @@ static struct amp_mgr *amp_mgr_create(struct l2cap_conn *conn)
 
 	return mgr;
 }
+
+struct l2cap_chan *a2mp_channel_create(struct l2cap_conn *conn,
+				       struct sk_buff *skb)
+{
+	struct amp_mgr *mgr;
+
+	mgr = amp_mgr_create(conn);
+
+	BT_DBG("mgr: %p chan %p", mgr, mgr->a2mp_chan);
+
+	return mgr->a2mp_chan;
+}
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index b5c4229..8c9250e 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -56,6 +56,7 @@
 #include <net/bluetooth/hci_core.h>
 #include <net/bluetooth/l2cap.h>
 #include <net/bluetooth/smp.h>
+#include <net/bluetooth/a2mp.h>
 
 bool disable_ertm;
 
@@ -4652,10 +4653,15 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk
 
 	chan = l2cap_get_chan_by_scid(conn, cid);
 	if (!chan) {
-		BT_DBG("unknown cid 0x%4.4x", cid);
-		/* Drop packet and return */
-		kfree_skb(skb);
-		return 0;
+		if (cid == L2CAP_CID_A2MP) {
+			chan = a2mp_channel_create(conn, skb);
+			l2cap_chan_lock(chan);
+		} else {
+			BT_DBG("unknown cid 0x%4.4x", cid);
+			/* Drop packet and return */
+			kfree_skb(skb);
+			return 0;
+		}
 	}
 
 	BT_DBG("chan %p, len %d", chan, skb->len);
-- 
1.7.9.5


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

* Re: [PATCHv1 00/17] Bluetooth A2MP implementation
  2012-05-18 14:25 [PATCHv1 00/17] Bluetooth A2MP implementation Andrei Emeltchenko
                   ` (16 preceding siblings ...)
  2012-05-18 14:25 ` [PATCHv1 17/17] Bluetooth: A2MP: Manage incoming connections Andrei Emeltchenko
@ 2012-05-18 20:57 ` Gustavo Padovan
  2012-05-23 15:37 ` [PATCHv2 00/19] " Andrei Emeltchenko
                   ` (2 subsequent siblings)
  20 siblings, 0 replies; 104+ messages in thread
From: Gustavo Padovan @ 2012-05-18 20:57 UTC (permalink / raw)
  To: Andrei Emeltchenko; +Cc: linux-bluetooth

Hi Andrei,

* Andrei Emeltchenko <Andrei.Emeltchenko.news@gmail.com> [2012-05-18 17:25:33 +0300]:

> From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
> 
> Basic A2MP implementation.

Please rebase against latest bluetooth-next, then we should be ready to apply
this.

	Gustavo

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

* Re: [PATCHv1 16/17] Bluetooth: A2MP: Handling fixed channels
  2012-05-18 14:25 ` [PATCHv1 16/17] Bluetooth: A2MP: Handling fixed channels Andrei Emeltchenko
@ 2012-05-21 22:28   ` Mat Martineau
  2012-05-22  8:12     ` Andrei Emeltchenko
  0 siblings, 1 reply; 104+ messages in thread
From: Mat Martineau @ 2012-05-21 22:28 UTC (permalink / raw)
  To: Andrei Emeltchenko; +Cc: linux-bluetooth, pkrystad


Hi Andrei -

On Fri, 18 May 2012, Andrei Emeltchenko wrote:

> From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
>
> A2MP fixed channel do not have sk
>
> Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
> ---
> include/net/bluetooth/l2cap.h |    1 +
> net/bluetooth/a2mp.c          |    3 +--
> net/bluetooth/l2cap_core.c    |   25 +++++++++++++++++++++++--
> 3 files changed, 25 insertions(+), 4 deletions(-)
>
> diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
> index 8cc739f..db47103 100644
> --- a/include/net/bluetooth/l2cap.h
> +++ b/include/net/bluetooth/l2cap.h
> @@ -582,6 +582,7 @@ struct l2cap_conn {
> #define L2CAP_CHAN_RAW			1
> #define L2CAP_CHAN_CONN_LESS		2
> #define L2CAP_CHAN_CONN_ORIENTED	3
> +#define L2CAP_CHAN_CONN_FIX_A2MP	4
>
> /* ----- L2CAP socket info ----- */
> #define l2cap_pi(sk) ((struct l2cap_pinfo *) sk)
> diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c
> index 4616da1..86b2078 100644
> --- a/net/bluetooth/a2mp.c
> +++ b/net/bluetooth/a2mp.c
> @@ -465,8 +465,7 @@ static struct l2cap_chan *a2mp_chan_open(struct l2cap_conn *conn)
>
> 	hci_conn_hold(conn->hcon);
>
> -	chan->omtu = L2CAP_A2MP_DEFAULT_MTU;
> -	chan->imtu = L2CAP_A2MP_DEFAULT_MTU;
> +	chan->chan_type = L2CAP_CHAN_CONN_FIX_A2MP;
> 	chan->flush_to = L2CAP_DEFAULT_FLUSH_TO;
>
> 	chan->ops = &a2mp_chan_ops;
> diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
> index ee333f0..b5c4229 100644
> --- a/net/bluetooth/l2cap_core.c
> +++ b/net/bluetooth/l2cap_core.c
> @@ -450,6 +450,13 @@ static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
> 		chan->omtu = L2CAP_DEFAULT_MTU;
> 		break;
>
> +	case L2CAP_CHAN_CONN_FIX_A2MP:
> +		chan->scid = L2CAP_CID_A2MP;
> +		chan->dcid = L2CAP_CID_A2MP;
> +		chan->omtu = L2CAP_A2MP_DEFAULT_MTU;
> +		chan->imtu = L2CAP_A2MP_DEFAULT_MTU;
> +		break;
> +
> 	default:
> 		/* Raw socket can send/recv signalling messages only */
> 		chan->scid = L2CAP_CID_SIGNALING;
> @@ -480,7 +487,7 @@ static void l2cap_chan_del(struct l2cap_chan *chan, int err)
> {
> 	struct sock *sk = chan->sk;
> 	struct l2cap_conn *conn = chan->conn;
> -	struct sock *parent = bt_sk(sk)->parent;
> +	struct sock *parent;
>
> 	__clear_chan_timer(chan);
>
> @@ -496,6 +503,9 @@ static void l2cap_chan_del(struct l2cap_chan *chan, int err)
> 		hci_conn_put(conn->hcon);
> 	}
>
> +	if (chan->chan_type == L2CAP_CHAN_CONN_FIX_A2MP)
> +		goto clean;
> +

Since this has more to do with socketless channels than A2MP, it might 
be better to do something more generic here like add a callback to 
l2cap_ops so this socket code can be removed from l2cap_core rather 
than worked around.

> 	lock_sock(sk);
>
> 	__l2cap_state_change(chan, BT_CLOSED);
> @@ -504,6 +514,7 @@ static void l2cap_chan_del(struct l2cap_chan *chan, int err)
> 	if (err)
> 		__l2cap_chan_set_err(chan, err);
>
> +	parent = bt_sk(sk)->parent;
> 	if (parent) {
> 		bt_accept_unlink(sk);
> 		parent->sk_data_ready(parent, 0);
> @@ -515,6 +526,7 @@ static void l2cap_chan_del(struct l2cap_chan *chan, int err)
> 	if (test_bit(CONF_NOT_COMPLETE, &chan->conf_state))
> 		return;
>
> +clean:
> 	skb_queue_purge(&chan->tx_q);
>
> 	if (chan->mode == L2CAP_MODE_ERTM) {
> @@ -992,6 +1004,9 @@ static void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *c
> 	if (!conn)
> 		return;
>
> +	if (chan->chan_type == L2CAP_CHAN_CONN_FIX_A2MP)
> +		return;
> +

There are places in the ERTM state machine that call 
l2cap_send_disconn_req() to tear down an unrecoverable ERTM 
connection.  If the connection remained up, I'm not sure how ERTM will 
behave.

I don't know that the spec is very clear about what to do 
when ERTM must disconnect the channel, but the channel is fixed.

I think it would be best to tell the owner of the channel (A2MP in 
this case) that the channel has been disconnected using the 
state_change l2cap op, even if no disconnect request is sent to the 
remote device.  This way a new A2MP fixed channel can be started up so 
there is some chance that the two sides of the A2MP ERTM connection 
can sync up again.


> 	if (chan->mode == L2CAP_MODE_ERTM) {
> 		__clear_retrans_timer(chan);
> 		__clear_monitor_timer(chan);
> @@ -1201,6 +1216,11 @@ static void l2cap_conn_ready(struct l2cap_conn *conn)
>
> 		l2cap_chan_lock(chan);
>
> +		if (chan->chan_type == L2CAP_CHAN_CONN_FIX_A2MP) {
> +			l2cap_chan_unlock(chan);
> +			continue;
> +		}
> +

This bypasses the socket code in that loop, but also means the state 
change is not sent to the AMP manager.  Is there a way to fix up the 
state change code in l2cap_ops so the socket code can be removed from 
l2cap_conn_ready and other socketless L2CAP channels will also work 
without special case code?

> 		if (conn->hcon->type == LE_LINK) {
> 			if (smp_conn_security(conn, chan->sec_level))
> 				l2cap_chan_ready(chan);
> @@ -1581,7 +1601,8 @@ static void l2cap_monitor_timeout(struct work_struct *work)
> 	l2cap_chan_lock(chan);
>
> 	if (chan->retry_count >= chan->remote_max_tx) {
> -		l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
> +		if (chan->chan_type != L2CAP_CHAN_CONN_FIX_A2MP)
> +			l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);

The spec defines the MaxTransmit value as 0xff for the A2MP channel, 
not 0x00 (for infinite retries).  There is therefore an expectation 
that the ERTM connection will reset after too many retries - and I 
don't think it is ok to skip the disconnect here.

> 		l2cap_chan_unlock(chan);
> 		l2cap_chan_put(chan);
> 		return;
> -- 
> 1.7.9.5

Regards,

--
Mat Martineau
Employee of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum


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

* Re: [PATCHv1 17/17] Bluetooth: A2MP: Manage incoming connections
  2012-05-18 14:25 ` [PATCHv1 17/17] Bluetooth: A2MP: Manage incoming connections Andrei Emeltchenko
@ 2012-05-21 22:45   ` Mat Martineau
  2012-05-22  7:37     ` Andrei Emeltchenko
  0 siblings, 1 reply; 104+ messages in thread
From: Mat Martineau @ 2012-05-21 22:45 UTC (permalink / raw)
  To: Andrei Emeltchenko; +Cc: linux-bluetooth


On Fri, 18 May 2012, Andrei Emeltchenko wrote:

> From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
>
> Handle incoming A2MP connection by creating AMP manager and
> processing A2MP messages.
>
> Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
> ---
> include/net/bluetooth/a2mp.h |    4 ++++
> net/bluetooth/a2mp.c         |   12 ++++++++++++
> net/bluetooth/l2cap_core.c   |   14 ++++++++++----
> 3 files changed, 26 insertions(+), 4 deletions(-)
>
> diff --git a/include/net/bluetooth/a2mp.h b/include/net/bluetooth/a2mp.h
> index 980c266..b4f74c6 100644
> --- a/include/net/bluetooth/a2mp.h
> +++ b/include/net/bluetooth/a2mp.h
> @@ -15,6 +15,8 @@
> #ifndef __A2MP_H
> #define __A2MP_H
>
> +#include <net/bluetooth/l2cap.h>
> +
> #define A2MP_FEAT_EXT	0x8000
>
> struct amp_mgr {
> @@ -119,5 +121,7 @@ struct a2mp_physlink_rsp {
>
> void amp_mgr_get(struct amp_mgr *mgr);
> int amp_mgr_put(struct amp_mgr *mgr);
> +struct l2cap_chan *a2mp_channel_create(struct l2cap_conn *conn,
> +				       struct sk_buff *skb);
>
> #endif /* __A2MP_H */
> diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c
> index 86b2078..dda297d 100644
> --- a/net/bluetooth/a2mp.c
> +++ b/net/bluetooth/a2mp.c
> @@ -544,3 +544,15 @@ static struct amp_mgr *amp_mgr_create(struct l2cap_conn *conn)
>
> 	return mgr;
> }
> +
> +struct l2cap_chan *a2mp_channel_create(struct l2cap_conn *conn,
> +				       struct sk_buff *skb)
> +{
> +	struct amp_mgr *mgr;
> +
> +	mgr = amp_mgr_create(conn);
> +
> +	BT_DBG("mgr: %p chan %p", mgr, mgr->a2mp_chan);
> +
> +	return mgr->a2mp_chan;
> +}
> diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
> index b5c4229..8c9250e 100644
> --- a/net/bluetooth/l2cap_core.c
> +++ b/net/bluetooth/l2cap_core.c
> @@ -56,6 +56,7 @@
> #include <net/bluetooth/hci_core.h>
> #include <net/bluetooth/l2cap.h>
> #include <net/bluetooth/smp.h>
> +#include <net/bluetooth/a2mp.h>
>
> bool disable_ertm;
>
> @@ -4652,10 +4653,15 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk
>
> 	chan = l2cap_get_chan_by_scid(conn, cid);
> 	if (!chan) {
> -		BT_DBG("unknown cid 0x%4.4x", cid);
> -		/* Drop packet and return */
> -		kfree_skb(skb);
> -		return 0;
> +		if (cid == L2CAP_CID_A2MP) {
> +			chan = a2mp_channel_create(conn, skb);

This allocates a new AMP manager for each incoming command, doesn't 
it?  I'd expect the manager to be created once when it is first 
needed, then remain active until the ACL is closed.

> +			l2cap_chan_lock(chan);
> +		} else {
> +			BT_DBG("unknown cid 0x%4.4x", cid);
> +			/* Drop packet and return */
> +			kfree_skb(skb);
> +			return 0;
> +		}
> 	}
>
> 	BT_DBG("chan %p, len %d", chan, skb->len);
> -- 
> 1.7.9.5

How do you plan to create an AMP manager if you don't get an A2MP 
command from the remote device first?

Regards,

--
Mat Martineau
Employee of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum


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

* Re: [PATCHv1 17/17] Bluetooth: A2MP: Manage incoming connections
  2012-05-21 22:45   ` Mat Martineau
@ 2012-05-22  7:37     ` Andrei Emeltchenko
  2012-05-22 17:38       ` Mat Martineau
  0 siblings, 1 reply; 104+ messages in thread
From: Andrei Emeltchenko @ 2012-05-22  7:37 UTC (permalink / raw)
  To: Mat Martineau; +Cc: linux-bluetooth

Hi Mat,

On Mon, May 21, 2012 at 03:45:38PM -0700, Mat Martineau wrote:
...
> >@@ -4652,10 +4653,15 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk
> >
> >	chan = l2cap_get_chan_by_scid(conn, cid);
> >	if (!chan) {
> >-		BT_DBG("unknown cid 0x%4.4x", cid);
> >-		/* Drop packet and return */
> >-		kfree_skb(skb);
> >-		return 0;
> >+		if (cid == L2CAP_CID_A2MP) {
> >+			chan = a2mp_channel_create(conn, skb);
> 
> This allocates a new AMP manager for each incoming command, doesn't
> it?  I'd expect the manager to be created once when it is first
> needed, then remain active until the ACL is closed.

No. If AMP channel exist it will be returned with l2cap_get_chan_by_scid.
Channel exist while ACL connection exist.

> >-- 
> >1.7.9.5
> 
> How do you plan to create an AMP manager if you don't get an A2MP
> command from the remote device first?

I have code which is not yet sent. Something like:

+void l2cap_discover_amp(struct l2cap_conn *conn)
+{
+	struct a2mp_discov_req req;
+	struct amp_mgr *mgr;
+
+	BT_DBG("%p", conn);
+
+	mgr = amp_mgr_lookup(conn);
+	if (!mgr) {
+		mgr = amp_mgr_create(conn);
+		if (!mgr)
+			return;
+		else
+			amp_mgr_get(mgr);
+	}
+
+	req.mtu = cpu_to_le16(L2CAP_A2MP_DEFAULT_MTU);
+	req.ext_feat = 0;
+	a2mp_send(mgr, A2MP_DISCOVER_REQ, 1, sizeof(req), &req);
+
+	amp_mgr_put(mgr);
+}

Best regards 
Andrei Emeltchenko 


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

* Re: [PATCHv1 16/17] Bluetooth: A2MP: Handling fixed channels
  2012-05-21 22:28   ` Mat Martineau
@ 2012-05-22  8:12     ` Andrei Emeltchenko
  2012-05-22 17:35       ` Mat Martineau
  0 siblings, 1 reply; 104+ messages in thread
From: Andrei Emeltchenko @ 2012-05-22  8:12 UTC (permalink / raw)
  To: Mat Martineau; +Cc: linux-bluetooth, pkrystad

Hi Mat,

Thanks for review,

On Mon, May 21, 2012 at 03:28:57PM -0700, Mat Martineau wrote:
> >@@ -480,7 +487,7 @@ static void l2cap_chan_del(struct l2cap_chan *chan, int err)
> >{
> >	struct sock *sk = chan->sk;
> >	struct l2cap_conn *conn = chan->conn;
> >-	struct sock *parent = bt_sk(sk)->parent;
> >+	struct sock *parent;
> >
> >	__clear_chan_timer(chan);
> >
> >@@ -496,6 +503,9 @@ static void l2cap_chan_del(struct l2cap_chan *chan, int err)
> >		hci_conn_put(conn->hcon);
> >	}
> >
> >+	if (chan->chan_type == L2CAP_CHAN_CONN_FIX_A2MP)
> >+		goto clean;
> >+
> 
> Since this has more to do with socketless channels than A2MP, it
> might be better to do something more generic here like add a
> callback to l2cap_ops so this socket code can be removed from
> l2cap_core rather than worked around.

This can be done. What would be good function name? l2cap_chan_del_cb,
l2cap_chan_unlink ?

The downside is that the code will be used only once ...

> 
> >	lock_sock(sk);
> >
> >	__l2cap_state_change(chan, BT_CLOSED);
> >@@ -504,6 +514,7 @@ static void l2cap_chan_del(struct l2cap_chan *chan, int err)
> >	if (err)
> >		__l2cap_chan_set_err(chan, err);
> >
> >+	parent = bt_sk(sk)->parent;
> >	if (parent) {
> >		bt_accept_unlink(sk);
> >		parent->sk_data_ready(parent, 0);
> >@@ -515,6 +526,7 @@ static void l2cap_chan_del(struct l2cap_chan *chan, int err)
> >	if (test_bit(CONF_NOT_COMPLETE, &chan->conf_state))
> >		return;
> >
> >+clean:
> >	skb_queue_purge(&chan->tx_q);
> >
> >	if (chan->mode == L2CAP_MODE_ERTM) {
> >@@ -992,6 +1004,9 @@ static void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *c
> >	if (!conn)
> >		return;
> >
> >+	if (chan->chan_type == L2CAP_CHAN_CONN_FIX_A2MP)
> >+		return;
> >+
> 
> There are places in the ERTM state machine that call
> l2cap_send_disconn_req() to tear down an unrecoverable ERTM
> connection.  If the connection remained up, I'm not sure how ERTM
> will behave.

I can rework this part so that in a case of fixed channel we do not send
Disc Req and do not lock sk. So this would adds clearing timers and then
return.

> I don't know that the spec is very clear about what to do when ERTM
> must disconnect the channel, but the channel is fixed.

I think we shall do nothing.

> I think it would be best to tell the owner of the channel (A2MP in
> this case) that the channel has been disconnected using the
> state_change l2cap op, even if no disconnect request is sent to the
> remote device.  This way a new A2MP fixed channel can be started up
> so there is some chance that the two sides of the A2MP ERTM
> connection can sync up again.

I can add state_change and the code would look like:

static void l2cap_send_disconn_req(struct l2cap_conn *conn, struct
l2cap_chan *chan, int err)
{
	struct sock *sk = chan->sk;
	struct l2cap_disconn_req req;

	if (!conn)
		return;

	if (chan->mode == L2CAP_MODE_ERTM) {
		__clear_retrans_timer(chan);
		__clear_monitor_timer(chan);
		__clear_ack_timer(chan);
	}

	if (chan->chan_type == L2CAP_CHAN_CONN_FIX_A2MP) {
		__l2cap_state_change(chan, BT_DISCONN);
		return;
	}

	req.dcid = cpu_to_le16(chan->dcid);
	req.scid = cpu_to_le16(chan->scid);
	l2cap_send_cmd(conn, l2cap_get_ident(conn),
			L2CAP_DISCONN_REQ, sizeof(req), &req);

	lock_sock(sk);
	__l2cap_state_change(chan, BT_DISCONN);
	__l2cap_chan_set_err(chan, err);
	release_sock(sk);
}

Then function might be renamed to l2cap_disconnect_chan()

> >	if (chan->mode == L2CAP_MODE_ERTM) {
> >		__clear_retrans_timer(chan);
> >		__clear_monitor_timer(chan);
> >@@ -1201,6 +1216,11 @@ static void l2cap_conn_ready(struct l2cap_conn *conn)
> >
> >		l2cap_chan_lock(chan);
> >
> >+		if (chan->chan_type == L2CAP_CHAN_CONN_FIX_A2MP) {
> >+			l2cap_chan_unlock(chan);
> >+			continue;
> >+		}
> >+
> 
> This bypasses the socket code in that loop, but also means the state
> change is not sent to the AMP manager.  

Yes, but state is already BT_CONNECTED for fixed channel so it does not
need to change.

> Is there a way to fix up the
> state change code in l2cap_ops so the socket code can be removed
> from l2cap_conn_ready and other socketless L2CAP channels will also
> work without special case code?

If we would invoke sk->sk_state_change(sk) each time we call state_change
it would be easily done. Otherwise we might need special ops for
sk_state_change.


> >		if (conn->hcon->type == LE_LINK) {
> >			if (smp_conn_security(conn, chan->sec_level))
> >				l2cap_chan_ready(chan);
> >@@ -1581,7 +1601,8 @@ static void l2cap_monitor_timeout(struct work_struct *work)
> >	l2cap_chan_lock(chan);
> >
> >	if (chan->retry_count >= chan->remote_max_tx) {
> >-		l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
> >+		if (chan->chan_type != L2CAP_CHAN_CONN_FIX_A2MP)
> >+			l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
> 
> The spec defines the MaxTransmit value as 0xff for the A2MP channel,
> not 0x00 (for infinite retries).  There is therefore an expectation
> that the ERTM connection will reset after too many retries - and I
> don't think it is ok to skip the disconnect here.

I will delete this chunk at all since we already check for fixed channel
in l2cap_send_disconn_req

Best regards 
Andrei Emeltchenko 


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

* Re: [PATCHv1 16/17] Bluetooth: A2MP: Handling fixed channels
  2012-05-22  8:12     ` Andrei Emeltchenko
@ 2012-05-22 17:35       ` Mat Martineau
  0 siblings, 0 replies; 104+ messages in thread
From: Mat Martineau @ 2012-05-22 17:35 UTC (permalink / raw)
  To: Andrei Emeltchenko; +Cc: linux-bluetooth, pkrystad


On Tue, 22 May 2012, Andrei Emeltchenko wrote:

> Hi Mat,
>
> Thanks for review,
>
> On Mon, May 21, 2012 at 03:28:57PM -0700, Mat Martineau wrote:
>>> @@ -480,7 +487,7 @@ static void l2cap_chan_del(struct l2cap_chan *chan, int err)
>>> {
>>> 	struct sock *sk = chan->sk;
>>> 	struct l2cap_conn *conn = chan->conn;
>>> -	struct sock *parent = bt_sk(sk)->parent;
>>> +	struct sock *parent;
>>>
>>> 	__clear_chan_timer(chan);
>>>
>>> @@ -496,6 +503,9 @@ static void l2cap_chan_del(struct l2cap_chan *chan, int err)
>>> 		hci_conn_put(conn->hcon);
>>> 	}
>>>
>>> +	if (chan->chan_type == L2CAP_CHAN_CONN_FIX_A2MP)
>>> +		goto clean;
>>> +
>>
>> Since this has more to do with socketless channels than A2MP, it
>> might be better to do something more generic here like add a
>> callback to l2cap_ops so this socket code can be removed from
>> l2cap_core rather than worked around.
>
> This can be done. What would be good function name? l2cap_chan_del_cb,
> l2cap_chan_unlink ?
>
> The downside is that the code will be used only once ...

I think the long term goal is to get all socket code out of 
l2cap_core.c and rework RFCOMM to directly use l2cap_chan instead of 
sockets, so the callback would be used elsewhere.

>>
>>> 	lock_sock(sk);
>>>
>>> 	__l2cap_state_change(chan, BT_CLOSED);
>>> @@ -504,6 +514,7 @@ static void l2cap_chan_del(struct l2cap_chan *chan, int err)
>>> 	if (err)
>>> 		__l2cap_chan_set_err(chan, err);
>>>
>>> +	parent = bt_sk(sk)->parent;
>>> 	if (parent) {
>>> 		bt_accept_unlink(sk);
>>> 		parent->sk_data_ready(parent, 0);
>>> @@ -515,6 +526,7 @@ static void l2cap_chan_del(struct l2cap_chan *chan, int err)
>>> 	if (test_bit(CONF_NOT_COMPLETE, &chan->conf_state))
>>> 		return;
>>>
>>> +clean:
>>> 	skb_queue_purge(&chan->tx_q);
>>>
>>> 	if (chan->mode == L2CAP_MODE_ERTM) {
>>> @@ -992,6 +1004,9 @@ static void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *c
>>> 	if (!conn)
>>> 		return;
>>>
>>> +	if (chan->chan_type == L2CAP_CHAN_CONN_FIX_A2MP)
>>> +		return;
>>> +
>>
>> There are places in the ERTM state machine that call
>> l2cap_send_disconn_req() to tear down an unrecoverable ERTM
>> connection.  If the connection remained up, I'm not sure how ERTM
>> will behave.
>
> I can rework this part so that in a case of fixed channel we do not send
> Disc Req and do not lock sk. So this would adds clearing timers and then
> return.

Ok.

>
>> I don't know that the spec is very clear about what to do when ERTM
>> must disconnect the channel, but the channel is fixed.
>
> I think we shall do nothing.
>
>> I think it would be best to tell the owner of the channel (A2MP in
>> this case) that the channel has been disconnected using the
>> state_change l2cap op, even if no disconnect request is sent to the
>> remote device.  This way a new A2MP fixed channel can be started up
>> so there is some chance that the two sides of the A2MP ERTM
>> connection can sync up again.
>
> I can add state_change and the code would look like:
>
> static void l2cap_send_disconn_req(struct l2cap_conn *conn, struct
> l2cap_chan *chan, int err)
> {
> 	struct sock *sk = chan->sk;
> 	struct l2cap_disconn_req req;
>
> 	if (!conn)
> 		return;
>
> 	if (chan->mode == L2CAP_MODE_ERTM) {
> 		__clear_retrans_timer(chan);
> 		__clear_monitor_timer(chan);
> 		__clear_ack_timer(chan);
> 	}
>
> 	if (chan->chan_type == L2CAP_CHAN_CONN_FIX_A2MP) {
> 		__l2cap_state_change(chan, BT_DISCONN);
> 		return;
> 	}
>
> 	req.dcid = cpu_to_le16(chan->dcid);
> 	req.scid = cpu_to_le16(chan->scid);
> 	l2cap_send_cmd(conn, l2cap_get_ident(conn),
> 			L2CAP_DISCONN_REQ, sizeof(req), &req);
>
> 	lock_sock(sk);
> 	__l2cap_state_change(chan, BT_DISCONN);
> 	__l2cap_chan_set_err(chan, err);
> 	release_sock(sk);
> }

Looks fine to me.  The A2MP fixed channel is a special case in this 
regard.

>
> Then function might be renamed to l2cap_disconnect_chan()
>
>>> 	if (chan->mode == L2CAP_MODE_ERTM) {
>>> 		__clear_retrans_timer(chan);
>>> 		__clear_monitor_timer(chan);
>>> @@ -1201,6 +1216,11 @@ static void l2cap_conn_ready(struct l2cap_conn *conn)
>>>
>>> 		l2cap_chan_lock(chan);
>>>
>>> +		if (chan->chan_type == L2CAP_CHAN_CONN_FIX_A2MP) {
>>> +			l2cap_chan_unlock(chan);
>>> +			continue;
>>> +		}
>>> +
>>
>> This bypasses the socket code in that loop, but also means the state
>> change is not sent to the AMP manager.
>
> Yes, but state is already BT_CONNECTED for fixed channel so it does not
> need to change.

Since the ERTM fixed channel can be created synchronously now (unlike 
the older Code Aurora Forum code), I think you're right that the state 
change notification isn't needed here any more.

>> Is there a way to fix up the
>> state change code in l2cap_ops so the socket code can be removed
>> from l2cap_conn_ready and other socketless L2CAP channels will also
>> work without special case code?
>
> If we would invoke sk->sk_state_change(sk) each time we call state_change
> it would be easily done. Otherwise we might need special ops for
> sk_state_change.

Right.  I'm not sure why they need to be separate - there may be 
some good reason, or maybe it's just hanging around from older code.

>>> 		if (conn->hcon->type == LE_LINK) {
>>> 			if (smp_conn_security(conn, chan->sec_level))
>>> 				l2cap_chan_ready(chan);
>>> @@ -1581,7 +1601,8 @@ static void l2cap_monitor_timeout(struct work_struct *work)
>>> 	l2cap_chan_lock(chan);
>>>
>>> 	if (chan->retry_count >= chan->remote_max_tx) {
>>> -		l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
>>> +		if (chan->chan_type != L2CAP_CHAN_CONN_FIX_A2MP)
>>> +			l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
>>
>> The spec defines the MaxTransmit value as 0xff for the A2MP channel,
>> not 0x00 (for infinite retries).  There is therefore an expectation
>> that the ERTM connection will reset after too many retries - and I
>> don't think it is ok to skip the disconnect here.
>
> I will delete this chunk at all since we already check for fixed channel
> in l2cap_send_disconn_req



--
Mat Martineau
Employee of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum


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

* Re: [PATCHv1 17/17] Bluetooth: A2MP: Manage incoming connections
  2012-05-22  7:37     ` Andrei Emeltchenko
@ 2012-05-22 17:38       ` Mat Martineau
  0 siblings, 0 replies; 104+ messages in thread
From: Mat Martineau @ 2012-05-22 17:38 UTC (permalink / raw)
  To: Andrei Emeltchenko; +Cc: linux-bluetooth, pkrystad


Andrei -

On Tue, 22 May 2012, Andrei Emeltchenko wrote:

> Hi Mat,
>
> On Mon, May 21, 2012 at 03:45:38PM -0700, Mat Martineau wrote:
> ...
>>> @@ -4652,10 +4653,15 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk
>>>
>>> 	chan = l2cap_get_chan_by_scid(conn, cid);
>>> 	if (!chan) {
>>> -		BT_DBG("unknown cid 0x%4.4x", cid);
>>> -		/* Drop packet and return */
>>> -		kfree_skb(skb);
>>> -		return 0;
>>> +		if (cid == L2CAP_CID_A2MP) {
>>> +			chan = a2mp_channel_create(conn, skb);
>>
>> This allocates a new AMP manager for each incoming command, doesn't
>> it?  I'd expect the manager to be created once when it is first
>> needed, then remain active until the ACL is closed.
>
> No. If AMP channel exist it will be returned with l2cap_get_chan_by_scid.
> Channel exist while ACL connection exist.

Oh, ok - I see that it is added to the channel list in l2cap_chan_add.


Thanks,
--
Mat Martineau
Employee of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum


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

* Re: [PATCHv1 01/17] Bluetooth: A2MP: Create A2MP channel
  2012-05-18 14:25 ` [PATCHv1 01/17] Bluetooth: A2MP: Create A2MP channel Andrei Emeltchenko
@ 2012-05-22 17:45   ` Mat Martineau
  2012-05-23  7:49     ` Andrei Emeltchenko
  0 siblings, 1 reply; 104+ messages in thread
From: Mat Martineau @ 2012-05-22 17:45 UTC (permalink / raw)
  To: Andrei Emeltchenko; +Cc: linux-bluetooth, pkrystad


Andrei -

On Fri, 18 May 2012, Andrei Emeltchenko wrote:

> From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
>
> Create and initialize fixed A2MP channel
>
> Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
> ---
> include/net/bluetooth/l2cap.h |    5 ++++
> net/bluetooth/Makefile        |    3 ++-
> net/bluetooth/a2mp.c          |   59 +++++++++++++++++++++++++++++++++++++++++
> net/bluetooth/l2cap_core.c    |    4 +--
> 4 files changed, 68 insertions(+), 3 deletions(-)
> create mode 100644 net/bluetooth/a2mp.c
>
> diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
> index 8fdfaca..8cc739f 100644
> --- a/include/net/bluetooth/l2cap.h
> +++ b/include/net/bluetooth/l2cap.h
> @@ -52,6 +52,8 @@
> #define L2CAP_CONN_TIMEOUT		msecs_to_jiffies(40000)
> #define L2CAP_INFO_TIMEOUT		msecs_to_jiffies(4000)
>
> +#define L2CAP_A2MP_DEFAULT_MTU		670
> +
> /* L2CAP socket address */
> struct sockaddr_l2 {
> 	sa_family_t	l2_family;
> @@ -232,6 +234,7 @@ struct l2cap_conn_rsp {
> /* channel indentifier */
> #define L2CAP_CID_SIGNALING	0x0001
> #define L2CAP_CID_CONN_LESS	0x0002
> +#define L2CAP_CID_A2MP		0x0003
> #define L2CAP_CID_LE_DATA	0x0004
> #define L2CAP_CID_LE_SIGNALING	0x0005
> #define L2CAP_CID_SMP		0x0006
> @@ -931,5 +934,7 @@ int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len,
> void l2cap_chan_busy(struct l2cap_chan *chan, int busy);
> int l2cap_chan_check_security(struct l2cap_chan *chan);
> void l2cap_chan_set_defaults(struct l2cap_chan *chan);
> +int l2cap_ertm_init(struct l2cap_chan *chan);
> +void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan);
>
> #endif /* __L2CAP_H */
> diff --git a/net/bluetooth/Makefile b/net/bluetooth/Makefile
> index 2dc5a57..fa6d94a 100644
> --- a/net/bluetooth/Makefile
> +++ b/net/bluetooth/Makefile
> @@ -9,4 +9,5 @@ obj-$(CONFIG_BT_CMTP)	+= cmtp/
> obj-$(CONFIG_BT_HIDP)	+= hidp/
>
> bluetooth-y := af_bluetooth.o hci_core.o hci_conn.o hci_event.o mgmt.o \
> -	hci_sock.o hci_sysfs.o l2cap_core.o l2cap_sock.o smp.o sco.o lib.o
> +	hci_sock.o hci_sysfs.o l2cap_core.o l2cap_sock.o smp.o sco.o lib.o \
> +	a2mp.o
> diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c
> new file mode 100644
> index 0000000..1f733b5
> --- /dev/null
> +++ b/net/bluetooth/a2mp.c
> @@ -0,0 +1,59 @@
> +/*
> +   Copyright (c) 2010,2011 Code Aurora Forum.  All rights reserved.
> +   Copyright (c) 2011,2012 Intel Corp.
> +
> +   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.
> +*/
> +
> +#include <net/bluetooth/bluetooth.h>
> +#include <net/bluetooth/hci_core.h>
> +#include <net/bluetooth/l2cap.h>
> +
> +static struct l2cap_ops a2mp_chan_ops = {
> +	.name = "L2CAP A2MP channel",
> +};
> +
> +static struct l2cap_chan *a2mp_chan_open(struct l2cap_conn *conn)
> +{
> +	struct l2cap_chan *chan;
> +
> +	chan = l2cap_chan_create();
> +	if (!chan)
> +		return NULL;
> +
> +	BT_DBG("chan %p", chan);
> +
> +	hci_conn_hold(conn->hcon);

Holding the hcon will keep the ACL open after all of the other L2CAP 
channels have closed (unless I missed some code later in the patch 
series).  The A2MP fixed channel should not keep the ACL open.  If the 
connection is not held here, then there shouldn't be a put in 
l2cap_chan_del for the A2MP channel either.

> +
> +	chan->omtu = L2CAP_A2MP_DEFAULT_MTU;
> +	chan->imtu = L2CAP_A2MP_DEFAULT_MTU;
> +	chan->flush_to = L2CAP_DEFAULT_FLUSH_TO;
> +
> +	chan->ops = &a2mp_chan_ops;
> +
> +	l2cap_chan_set_defaults(chan);
> +	chan->remote_max_tx = chan->max_tx;
> +	chan->remote_tx_win = chan->tx_win;
> +
> +	chan->retrans_timeout = L2CAP_DEFAULT_RETRANS_TO;
> +	chan->monitor_timeout = L2CAP_DEFAULT_MONITOR_TO;
> +
> +	skb_queue_head_init(&chan->tx_q);
> +
> +	chan->mode = L2CAP_MODE_ERTM;
> +	l2cap_ertm_init(chan);
> +
> +	l2cap_chan_add(conn, chan);
> +
> +	chan->remote_mps = chan->omtu;
> +	chan->mps = chan->omtu;
> +
> +	return chan;
> +}
> diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
> index 65e56d5..ee333f0 100644
> --- a/net/bluetooth/l2cap_core.c
> +++ b/net/bluetooth/l2cap_core.c
> @@ -469,7 +469,7 @@ static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
> 	list_add(&chan->list, &conn->chan_l);
> }
>
> -static void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
> +void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
> {
> 	mutex_lock(&conn->chan_lock);
> 	__l2cap_chan_add(conn, chan);
> @@ -2349,7 +2349,7 @@ static void l2cap_ack_timeout(struct work_struct *work)
> 	l2cap_chan_put(chan);
> }
>
> -static inline int l2cap_ertm_init(struct l2cap_chan *chan)
> +int l2cap_ertm_init(struct l2cap_chan *chan)
> {
> 	int err;
>
> -- 
> 1.7.9.5


Regards,
--
Mat Martineau
Employee of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum



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

* Re: [PATCHv1 01/17] Bluetooth: A2MP: Create A2MP channel
  2012-05-22 17:45   ` Mat Martineau
@ 2012-05-23  7:49     ` Andrei Emeltchenko
  2012-05-23 15:44       ` Mat Martineau
  0 siblings, 1 reply; 104+ messages in thread
From: Andrei Emeltchenko @ 2012-05-23  7:49 UTC (permalink / raw)
  To: Mat Martineau; +Cc: linux-bluetooth, pkrystad

Hi Mat,

On Tue, May 22, 2012 at 10:45:07AM -0700, Mat Martineau wrote:
> >+static struct l2cap_chan *a2mp_chan_open(struct l2cap_conn *conn)
> >+{
> >+	struct l2cap_chan *chan;
> >+
> >+	chan = l2cap_chan_create();
> >+	if (!chan)
> >+		return NULL;
> >+
> >+	BT_DBG("chan %p", chan);
> >+
> >+	hci_conn_hold(conn->hcon);
> 
> Holding the hcon will keep the ACL open after all of the other L2CAP
> channels have closed (unless I missed some code later in the patch
> series).  The A2MP fixed channel should not keep the ACL open.  If
> the connection is not held here, then there shouldn't be a put in
> l2cap_chan_del for the A2MP channel either.

l2cap_chan_del makes hci_conn_put, also for a2mp channel. The behavior is
the same for fixed and normal channels.

Best regards 
Andrei Emeltchenko 
 

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

* [PATCHv2 00/19] Bluetooth A2MP implementation
  2012-05-18 14:25 [PATCHv1 00/17] Bluetooth A2MP implementation Andrei Emeltchenko
                   ` (17 preceding siblings ...)
  2012-05-18 20:57 ` [PATCHv1 00/17] Bluetooth A2MP implementation Gustavo Padovan
@ 2012-05-23 15:37 ` Andrei Emeltchenko
  2012-05-23 15:37   ` [PATCHv2 01/19] Bluetooth: Add unlink to L2CAP channel ops Andrei Emeltchenko
                     ` (18 more replies)
  2012-05-24 11:38 ` [PATCHv3 00/18] Bluetooth A2MP implementation Andrei Emeltchenko
  2012-05-29 10:59 ` [PATCHv4 00/17] Bluetooth A2MP implementation Andrei Emeltchenko
  20 siblings, 19 replies; 104+ messages in thread
From: Andrei Emeltchenko @ 2012-05-23 15:37 UTC (permalink / raw)
  To: linux-bluetooth

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

Basic A2MP implementation.

Changes:
	* PATCHv2: Rebased against recent changes, changed amp_mgr list to pointer
	in hci_conn, reworked handling fixed channels and create A2MP channel patches,
	adding unlink and ready callbacks to get rid of socket dependecies in L2CAP and
	other minor fixes.
	* PATCHv1: Rebasing against latest tree and minor fixes.
	* RFCv7: Taking comments from review in linux-bluetooth.
	* RFCv6: Remove some unneded check for sk since they are in different path
	(A2MP decoded as a data channel wrt L2CAP signalling channel). Style fixes.
	* RFCv5: Fix memory leaks, sparse warnings and taking comments from upstream.
	* RFCv4: redesign code to use l2cap channel lock instead of socket lock
	and general modifications. Basic implementation of HCI callback interface.
	* RFCv3: redesign code to use l2cap functions instead of kernel sockets
	L2CAP functions modified to work with channels without sk.
	* RFCv2: rebased against "workqueue" patches.
	* RFCv1: added refcnt to amp_mgr, fixed sleeping in atomic

Initially code was based of reference implementations below:

References: Code Aurora (git://codeaurora.org/kernel/msm.git) and Atheros
(search for: [PATCH 2/3] Add a2mp protocol/AMP manager, by Atheros Linux BT3)
implementations.

Andrei Emeltchenko (19):
  Bluetooth: Add unlink to L2CAP channel ops
  Bluetooth: Add ready to L2CAP channel ops
  Bluetooth: A2MP: Create A2MP channel
  Bluetooth: A2MP: AMP Manager basic functions
  Bluetooth: A2MP: Build and Send msg helpers
  Bluetooth: A2MP: Add chan callbacks
  Bluetooth: A2MP: Definitions for A2MP commands
  Bluetooth: A2MP: Define A2MP status codes
  Bluetooth: A2MP: Process A2MP messages
  Bluetooth: A2MP: Process A2MP Command Reject
  Bluetooth: A2MP: Process A2MP Discover Request
  Bluetooth: A2MP: Process A2MP Change Notify
  Bluetooth: A2MP: Process A2MP Get Info Request
  Bluetooth: A2MP: Process A2MP Get AMP Assoc Request
  Bluetooth: A2MP: Process A2MP Create Physlink Request
  Bluetooth: A2MP: Process A2MP Disc Physlink Request
  Bluetooth: A2MP: Process A2MP Command Responses
  Bluetooth: A2MP: Handling fixed channels
  Bluetooth: A2MP: Manage incoming connections

 include/net/bluetooth/a2mp.h     |  126 +++++++++
 include/net/bluetooth/hci.h      |    3 +
 include/net/bluetooth/hci_core.h |   14 +
 include/net/bluetooth/l2cap.h    |    9 +
 net/bluetooth/Makefile           |    3 +-
 net/bluetooth/a2mp.c             |  566 ++++++++++++++++++++++++++++++++++++++
 net/bluetooth/hci_conn.c         |    4 +
 net/bluetooth/l2cap_core.c       |   98 +++----
 net/bluetooth/l2cap_sock.c       |   53 ++++
 9 files changed, 820 insertions(+), 56 deletions(-)
 create mode 100644 include/net/bluetooth/a2mp.h
 create mode 100644 net/bluetooth/a2mp.c

-- 
1.7.9.5


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

* [PATCHv2 01/19] Bluetooth: Add unlink to L2CAP channel ops
  2012-05-23 15:37 ` [PATCHv2 00/19] " Andrei Emeltchenko
@ 2012-05-23 15:37   ` Andrei Emeltchenko
  2012-05-23 23:13     ` Mat Martineau
  2012-05-23 15:37   ` [PATCHv2 02/19] Bluetooth: Add ready " Andrei Emeltchenko
                     ` (17 subsequent siblings)
  18 siblings, 1 reply; 104+ messages in thread
From: Andrei Emeltchenko @ 2012-05-23 15:37 UTC (permalink / raw)
  To: linux-bluetooth

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

This helps to separate socket and socketless code. Now socket related
operations moved to l2cap_sock in unlink callback for channels with sk.

Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
 include/net/bluetooth/l2cap.h |    1 +
 net/bluetooth/l2cap_core.c    |   19 ++-----------------
 net/bluetooth/l2cap_sock.c    |   25 +++++++++++++++++++++++++
 3 files changed, 28 insertions(+), 17 deletions(-)

diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index 0142257..a017249 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -529,6 +529,7 @@ struct l2cap_ops {
 	void			(*state_change) (void *data, int state);
 	struct sk_buff		*(*alloc_skb) (struct l2cap_chan *chan,
 					       unsigned long len, int nb);
+	void			(*unlink) (struct l2cap_chan *chan, int err);
 };
 
 struct l2cap_conn {
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index e31b005..c81b828 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -493,9 +493,7 @@ static void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
 
 static void l2cap_chan_del(struct l2cap_chan *chan, int err)
 {
-	struct sock *sk = chan->sk;
 	struct l2cap_conn *conn = chan->conn;
-	struct sock *parent = bt_sk(sk)->parent;
 
 	__clear_chan_timer(chan);
 
@@ -511,21 +509,8 @@ static void l2cap_chan_del(struct l2cap_chan *chan, int err)
 		hci_conn_put(conn->hcon);
 	}
 
-	lock_sock(sk);
-
-	__l2cap_state_change(chan, BT_CLOSED);
-	sock_set_flag(sk, SOCK_ZAPPED);
-
-	if (err)
-		__l2cap_chan_set_err(chan, err);
-
-	if (parent) {
-		bt_accept_unlink(sk);
-		parent->sk_data_ready(parent, 0);
-	} else
-		sk->sk_state_change(sk);
-
-	release_sock(sk);
+	if (chan->ops->unlink)
+		chan->ops->unlink(chan, err);
 
 	if (test_bit(CONF_NOT_COMPLETE, &chan->conf_state))
 		return;
diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c
index 4d36605..6749d11 100644
--- a/net/bluetooth/l2cap_sock.c
+++ b/net/bluetooth/l2cap_sock.c
@@ -954,6 +954,30 @@ static struct sk_buff *l2cap_sock_alloc_skb_cb(struct l2cap_chan *chan,
 	return skb;
 }
 
+static void l2cap_sock_unlink_cb(struct l2cap_chan *chan, int err)
+{
+	struct sock *sk = chan->sk;
+	struct sock *parent = bt_sk(sk)->parent;
+
+	lock_sock(sk);
+
+	chan->state = BT_CLOSED;
+	sk->sk_state = BT_CLOSED;
+	sock_set_flag(sk, SOCK_ZAPPED);
+
+	if (err)
+		sk->sk_err = err;
+
+	parent = bt_sk(sk)->parent;
+	if (parent) {
+		bt_accept_unlink(sk);
+		parent->sk_data_ready(parent, 0);
+	} else
+		sk->sk_state_change(sk);
+
+	release_sock(sk);
+}
+
 static struct l2cap_ops l2cap_chan_ops = {
 	.name		= "L2CAP Socket Interface",
 	.new_connection	= l2cap_sock_new_connection_cb,
@@ -961,6 +985,7 @@ static struct l2cap_ops l2cap_chan_ops = {
 	.close		= l2cap_sock_close_cb,
 	.state_change	= l2cap_sock_state_change_cb,
 	.alloc_skb	= l2cap_sock_alloc_skb_cb,
+	.unlink		= l2cap_sock_unlink_cb,
 };
 
 static void l2cap_sock_destruct(struct sock *sk)
-- 
1.7.9.5


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

* [PATCHv2 02/19] Bluetooth: Add ready to L2CAP channel ops
  2012-05-23 15:37 ` [PATCHv2 00/19] " Andrei Emeltchenko
  2012-05-23 15:37   ` [PATCHv2 01/19] Bluetooth: Add unlink to L2CAP channel ops Andrei Emeltchenko
@ 2012-05-23 15:37   ` Andrei Emeltchenko
  2012-05-23 23:16     ` Mat Martineau
  2012-05-23 15:37   ` [PATCHv2 03/19] Bluetooth: A2MP: Create A2MP channel Andrei Emeltchenko
                     ` (16 subsequent siblings)
  18 siblings, 1 reply; 104+ messages in thread
From: Andrei Emeltchenko @ 2012-05-23 15:37 UTC (permalink / raw)
  To: linux-bluetooth

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

Addings ops->ready() helps to separate socket and socketless
L2CAP channels.

Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
 include/net/bluetooth/l2cap.h |    1 +
 net/bluetooth/l2cap_core.c    |   42 +++++++++++------------------------------
 net/bluetooth/l2cap_sock.c    |   28 +++++++++++++++++++++++++++
 3 files changed, 40 insertions(+), 31 deletions(-)

diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index a017249..83a67e8 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -530,6 +530,7 @@ struct l2cap_ops {
 	struct sk_buff		*(*alloc_skb) (struct l2cap_chan *chan,
 					       unsigned long len, int nb);
 	void			(*unlink) (struct l2cap_chan *chan, int err);
+	void			(*ready) (struct l2cap_chan *chan);
 };
 
 struct l2cap_conn {
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index c81b828..d5ea8af 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -407,7 +407,7 @@ struct l2cap_chan *l2cap_chan_create(void)
 
 	atomic_set(&chan->refcnt, 1);
 
-	/* This flag is cleared in l2cap_chan_ready() */
+	/* This flag is cleared in l2cap chan ops->ready() */
 	set_bit(CONF_NOT_COMPLETE, &chan->conf_state);
 
 	BT_DBG("chan %p", chan);
@@ -953,36 +953,13 @@ static void l2cap_send_conn_req(struct l2cap_chan *chan)
 	l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_REQ, sizeof(req), &req);
 }
 
-static void l2cap_chan_ready(struct l2cap_chan *chan)
-{
-	struct sock *sk = chan->sk;
-	struct sock *parent;
-
-	lock_sock(sk);
-
-	parent = bt_sk(sk)->parent;
-
-	BT_DBG("sk %p, parent %p", sk, parent);
-
-	/* This clears all conf flags, including CONF_NOT_COMPLETE */
-	chan->conf_state = 0;
-	__clear_chan_timer(chan);
-
-	__l2cap_state_change(chan, BT_CONNECTED);
-	sk->sk_state_change(sk);
-
-	if (parent)
-		parent->sk_data_ready(parent, 0);
-
-	release_sock(sk);
-}
-
 static void l2cap_do_start(struct l2cap_chan *chan)
 {
 	struct l2cap_conn *conn = chan->conn;
 
 	if (conn->hcon->type == LE_LINK) {
-		l2cap_chan_ready(chan);
+		if (chan->ops->ready)
+			chan->ops->ready(chan);
 		return;
 	}
 
@@ -1242,8 +1219,8 @@ static void l2cap_conn_ready(struct l2cap_conn *conn)
 
 		if (conn->hcon->type == LE_LINK) {
 			if (smp_conn_security(conn, chan->sec_level))
-				l2cap_chan_ready(chan);
-
+				if (chan->ops->ready)
+					chan->ops->ready(chan);
 		} else if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
 			struct sock *sk = chan->sk;
 			__clear_chan_timer(chan);
@@ -3639,7 +3616,8 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr
 		if (err < 0)
 			l2cap_send_disconn_req(chan->conn, chan, -err);
 		else
-			l2cap_chan_ready(chan);
+			if (chan->ops->ready)
+				chan->ops->ready(chan);
 
 		goto unlock;
 	}
@@ -3770,7 +3748,8 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr
 		if (err < 0)
 			l2cap_send_disconn_req(chan->conn, chan, -err);
 		else
-			l2cap_chan_ready(chan);
+			if (chan->ops->ready)
+				chan->ops->ready(chan);
 	}
 
 done:
@@ -5420,7 +5399,8 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
 		if (chan->scid == L2CAP_CID_LE_DATA) {
 			if (!status && encrypt) {
 				chan->sec_level = hcon->sec_level;
-				l2cap_chan_ready(chan);
+				if (chan->ops->ready)
+					chan->ops->ready(chan);
 			}
 
 			l2cap_chan_unlock(chan);
diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c
index 6749d11..2e078c4 100644
--- a/net/bluetooth/l2cap_sock.c
+++ b/net/bluetooth/l2cap_sock.c
@@ -978,6 +978,33 @@ static void l2cap_sock_unlink_cb(struct l2cap_chan *chan, int err)
 	release_sock(sk);
 }
 
+static void l2cap_sock_chan_ready_cb(struct l2cap_chan *chan)
+{
+	struct sock *sk = chan->sk;
+	struct sock *parent;
+
+	lock_sock(sk);
+
+	parent = bt_sk(sk)->parent;
+
+	BT_DBG("sk %p, parent %p", sk, parent);
+
+	__clear_chan_timer(chan);
+
+	/* This clears all conf flags, including CONF_NOT_COMPLETE */
+	chan->conf_state = 0;
+
+	chan->state = BT_CONNECTED;
+	sk->sk_state = BT_CONNECTED;
+
+	sk->sk_state_change(sk);
+
+	if (parent)
+		parent->sk_data_ready(parent, 0);
+
+	release_sock(sk);
+}
+
 static struct l2cap_ops l2cap_chan_ops = {
 	.name		= "L2CAP Socket Interface",
 	.new_connection	= l2cap_sock_new_connection_cb,
@@ -986,6 +1013,7 @@ static struct l2cap_ops l2cap_chan_ops = {
 	.state_change	= l2cap_sock_state_change_cb,
 	.alloc_skb	= l2cap_sock_alloc_skb_cb,
 	.unlink		= l2cap_sock_unlink_cb,
+	.ready		= l2cap_sock_chan_ready_cb,
 };
 
 static void l2cap_sock_destruct(struct sock *sk)
-- 
1.7.9.5


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

* [PATCHv2 03/19] Bluetooth: A2MP: Create A2MP channel
  2012-05-23 15:37 ` [PATCHv2 00/19] " Andrei Emeltchenko
  2012-05-23 15:37   ` [PATCHv2 01/19] Bluetooth: Add unlink to L2CAP channel ops Andrei Emeltchenko
  2012-05-23 15:37   ` [PATCHv2 02/19] Bluetooth: Add ready " Andrei Emeltchenko
@ 2012-05-23 15:37   ` Andrei Emeltchenko
  2012-05-23 15:37   ` [PATCHv2 04/19] Bluetooth: A2MP: AMP Manager basic functions Andrei Emeltchenko
                     ` (15 subsequent siblings)
  18 siblings, 0 replies; 104+ messages in thread
From: Andrei Emeltchenko @ 2012-05-23 15:37 UTC (permalink / raw)
  To: linux-bluetooth

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

Create and initialize fixed A2MP channel

Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
 include/net/bluetooth/l2cap.h |    6 ++++
 net/bluetooth/Makefile        |    3 +-
 net/bluetooth/a2mp.c          |   67 +++++++++++++++++++++++++++++++++++++++++
 net/bluetooth/l2cap_core.c    |    6 ++--
 4 files changed, 78 insertions(+), 4 deletions(-)
 create mode 100644 net/bluetooth/a2mp.c

diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index 83a67e8..b022329 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -52,6 +52,8 @@
 #define L2CAP_CONN_TIMEOUT		msecs_to_jiffies(40000)
 #define L2CAP_INFO_TIMEOUT		msecs_to_jiffies(4000)
 
+#define L2CAP_A2MP_DEFAULT_MTU		670
+
 /* L2CAP socket address */
 struct sockaddr_l2 {
 	sa_family_t	l2_family;
@@ -232,6 +234,7 @@ struct l2cap_conn_rsp {
 /* channel indentifier */
 #define L2CAP_CID_SIGNALING	0x0001
 #define L2CAP_CID_CONN_LESS	0x0002
+#define L2CAP_CID_A2MP		0x0003
 #define L2CAP_CID_LE_DATA	0x0004
 #define L2CAP_CID_LE_SIGNALING	0x0005
 #define L2CAP_CID_SMP		0x0006
@@ -752,5 +755,8 @@ int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len,
 void l2cap_chan_busy(struct l2cap_chan *chan, int busy);
 int l2cap_chan_check_security(struct l2cap_chan *chan);
 void l2cap_chan_set_defaults(struct l2cap_chan *chan);
+int l2cap_ertm_init(struct l2cap_chan *chan);
+void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan);
+void l2cap_chan_del(struct l2cap_chan *chan, int err);
 
 #endif /* __L2CAP_H */
diff --git a/net/bluetooth/Makefile b/net/bluetooth/Makefile
index 2dc5a57..fa6d94a 100644
--- a/net/bluetooth/Makefile
+++ b/net/bluetooth/Makefile
@@ -9,4 +9,5 @@ obj-$(CONFIG_BT_CMTP)	+= cmtp/
 obj-$(CONFIG_BT_HIDP)	+= hidp/
 
 bluetooth-y := af_bluetooth.o hci_core.o hci_conn.o hci_event.o mgmt.o \
-	hci_sock.o hci_sysfs.o l2cap_core.o l2cap_sock.o smp.o sco.o lib.o
+	hci_sock.o hci_sysfs.o l2cap_core.o l2cap_sock.o smp.o sco.o lib.o \
+	a2mp.o
diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c
new file mode 100644
index 0000000..d1574f5
--- /dev/null
+++ b/net/bluetooth/a2mp.c
@@ -0,0 +1,67 @@
+/*
+   Copyright (c) 2010,2011 Code Aurora Forum.  All rights reserved.
+   Copyright (c) 2011,2012 Intel Corp.
+
+   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.
+*/
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+#include <net/bluetooth/l2cap.h>
+
+static struct l2cap_ops a2mp_chan_ops = {
+	.name = "L2CAP A2MP channel",
+};
+
+static struct l2cap_chan *a2mp_chan_open(struct l2cap_conn *conn)
+{
+	struct l2cap_chan *chan;
+	int err;
+
+	chan = l2cap_chan_create();
+	if (!chan)
+		return NULL;
+
+	BT_DBG("chan %p", chan);
+
+	hci_conn_hold(conn->hcon);
+
+	chan->omtu = L2CAP_A2MP_DEFAULT_MTU;
+	chan->imtu = L2CAP_A2MP_DEFAULT_MTU;
+	chan->flush_to = L2CAP_DEFAULT_FLUSH_TO;
+
+	chan->ops = &a2mp_chan_ops;
+
+	l2cap_chan_set_defaults(chan);
+	chan->remote_max_tx = chan->max_tx;
+	chan->remote_tx_win = chan->tx_win;
+
+	chan->retrans_timeout = L2CAP_DEFAULT_RETRANS_TO;
+	chan->monitor_timeout = L2CAP_DEFAULT_MONITOR_TO;
+
+	skb_queue_head_init(&chan->tx_q);
+
+	chan->mode = L2CAP_MODE_ERTM;
+
+	err = l2cap_ertm_init(chan);
+	if (err < 0) {
+		l2cap_chan_del(chan, 0);
+		return NULL;
+	}
+
+	chan->conf_state = 0;
+
+	l2cap_chan_add(conn, chan);
+
+	chan->remote_mps = chan->omtu;
+	chan->mps = chan->omtu;
+
+	return chan;
+}
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index d5ea8af..988ee09 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -484,14 +484,14 @@ static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
 	list_add(&chan->list, &conn->chan_l);
 }
 
-static void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
+void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
 {
 	mutex_lock(&conn->chan_lock);
 	__l2cap_chan_add(conn, chan);
 	mutex_unlock(&conn->chan_lock);
 }
 
-static void l2cap_chan_del(struct l2cap_chan *chan, int err)
+void l2cap_chan_del(struct l2cap_chan *chan, int err)
 {
 	struct l2cap_conn *conn = chan->conn;
 
@@ -2712,7 +2712,7 @@ static void l2cap_ack_timeout(struct work_struct *work)
 	l2cap_chan_put(chan);
 }
 
-static inline int l2cap_ertm_init(struct l2cap_chan *chan)
+int l2cap_ertm_init(struct l2cap_chan *chan)
 {
 	int err;
 
-- 
1.7.9.5


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

* [PATCHv2 04/19] Bluetooth: A2MP: AMP Manager basic functions
  2012-05-23 15:37 ` [PATCHv2 00/19] " Andrei Emeltchenko
                     ` (2 preceding siblings ...)
  2012-05-23 15:37   ` [PATCHv2 03/19] Bluetooth: A2MP: Create A2MP channel Andrei Emeltchenko
@ 2012-05-23 15:37   ` Andrei Emeltchenko
  2012-05-23 15:37   ` [PATCHv2 05/19] Bluetooth: A2MP: Build and Send msg helpers Andrei Emeltchenko
                     ` (14 subsequent siblings)
  18 siblings, 0 replies; 104+ messages in thread
From: Andrei Emeltchenko @ 2012-05-23 15:37 UTC (permalink / raw)
  To: linux-bluetooth

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

Define AMP Manager and some basic functions.

Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
 include/net/bluetooth/a2mp.h     |   30 +++++++++++++++++++++
 include/net/bluetooth/hci_core.h |    1 +
 net/bluetooth/a2mp.c             |   54 ++++++++++++++++++++++++++++++++++++++
 net/bluetooth/hci_conn.c         |    4 +++
 4 files changed, 89 insertions(+)
 create mode 100644 include/net/bluetooth/a2mp.h

diff --git a/include/net/bluetooth/a2mp.h b/include/net/bluetooth/a2mp.h
new file mode 100644
index 0000000..ff47540
--- /dev/null
+++ b/include/net/bluetooth/a2mp.h
@@ -0,0 +1,30 @@
+/*
+   Copyright (c) 2010,2011 Code Aurora Forum.  All rights reserved.
+   Copyright (c) 2011,2012 Intel Corp.
+
+   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 __A2MP_H
+#define __A2MP_H
+
+struct amp_mgr {
+	struct l2cap_conn	*l2cap_conn;
+	struct l2cap_chan	*a2mp_chan;
+	struct kref		kref;
+	__u8			ident;
+	__u8			handle;
+	unsigned long		flags;
+};
+
+void amp_mgr_get(struct amp_mgr *mgr);
+int amp_mgr_put(struct amp_mgr *mgr);
+
+#endif /* __A2MP_H */
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index d584a47..6e64b76 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -332,6 +332,7 @@ struct hci_conn {
 	void		*l2cap_data;
 	void		*sco_data;
 	void		*smp_conn;
+	struct amp_mgr	*amp_mgr;
 
 	struct hci_conn	*link;
 
diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c
index d1574f5..ea900fb 100644
--- a/net/bluetooth/a2mp.c
+++ b/net/bluetooth/a2mp.c
@@ -15,6 +15,7 @@
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
 #include <net/bluetooth/l2cap.h>
+#include <net/bluetooth/a2mp.h>
 
 static struct l2cap_ops a2mp_chan_ops = {
 	.name = "L2CAP A2MP channel",
@@ -65,3 +66,56 @@ static struct l2cap_chan *a2mp_chan_open(struct l2cap_conn *conn)
 
 	return chan;
 }
+
+/* AMP Manager functions */
+void amp_mgr_get(struct amp_mgr *mgr)
+{
+	BT_DBG("mgr %p", mgr);
+
+	kref_get(&mgr->kref);
+}
+
+static void amp_mgr_destroy(struct kref *kref)
+{
+	struct amp_mgr *mgr = container_of(kref, struct amp_mgr, kref);
+
+	BT_DBG("mgr %p", mgr);
+
+	kfree(mgr);
+}
+
+int amp_mgr_put(struct amp_mgr *mgr)
+{
+	BT_DBG("mgr %p", mgr);
+
+	return kref_put(&mgr->kref, &amp_mgr_destroy);
+}
+
+static struct amp_mgr *amp_mgr_create(struct l2cap_conn *conn)
+{
+	struct amp_mgr *mgr;
+	struct l2cap_chan *chan;
+
+	mgr = kzalloc(sizeof(*mgr), GFP_KERNEL);
+	if (!mgr)
+		return NULL;
+
+	BT_DBG("conn %p mgr %p", conn, mgr);
+
+	mgr->l2cap_conn = conn;
+
+	chan = a2mp_chan_open(conn);
+	if (!chan) {
+		kfree(mgr);
+		return NULL;
+	}
+
+	mgr->a2mp_chan = chan;
+	chan->data = mgr;
+
+	conn->hcon->amp_mgr = mgr;
+
+	kref_init(&mgr->kref);
+
+	return mgr;
+}
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index 8163ee1..111e549 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -28,6 +28,7 @@
 
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
+#include <net/bluetooth/a2mp.h>
 
 static void hci_le_connect(struct hci_conn *conn)
 {
@@ -411,6 +412,9 @@ int hci_conn_del(struct hci_conn *conn)
 
 	hci_chan_list_flush(conn);
 
+	if (conn->amp_mgr)
+		amp_mgr_put(conn->amp_mgr);
+
 	hci_conn_hash_del(hdev, conn);
 	if (hdev->notify)
 		hdev->notify(hdev, HCI_NOTIFY_CONN_DEL);
-- 
1.7.9.5


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

* [PATCHv2 05/19] Bluetooth: A2MP: Build and Send msg helpers
  2012-05-23 15:37 ` [PATCHv2 00/19] " Andrei Emeltchenko
                     ` (3 preceding siblings ...)
  2012-05-23 15:37   ` [PATCHv2 04/19] Bluetooth: A2MP: AMP Manager basic functions Andrei Emeltchenko
@ 2012-05-23 15:37   ` Andrei Emeltchenko
  2012-05-23 15:37   ` [PATCHv2 06/19] Bluetooth: A2MP: Add chan callbacks Andrei Emeltchenko
                     ` (13 subsequent siblings)
  18 siblings, 0 replies; 104+ messages in thread
From: Andrei Emeltchenko @ 2012-05-23 15:37 UTC (permalink / raw)
  To: linux-bluetooth

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

Helper function to build and send A2MP messages.

Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
 include/net/bluetooth/a2mp.h |    7 +++++++
 net/bluetooth/a2mp.c         |   46 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 53 insertions(+)

diff --git a/include/net/bluetooth/a2mp.h b/include/net/bluetooth/a2mp.h
index ff47540..654df60 100644
--- a/include/net/bluetooth/a2mp.h
+++ b/include/net/bluetooth/a2mp.h
@@ -24,6 +24,13 @@ struct amp_mgr {
 	unsigned long		flags;
 };
 
+struct a2mp_cmd {
+	__u8	code;
+	__u8	ident;
+	__le16	len;
+	__u8	data[0];
+} __packed;
+
 void amp_mgr_get(struct amp_mgr *mgr);
 int amp_mgr_put(struct amp_mgr *mgr);
 
diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c
index ea900fb..e7e5f5f 100644
--- a/net/bluetooth/a2mp.c
+++ b/net/bluetooth/a2mp.c
@@ -17,6 +17,52 @@
 #include <net/bluetooth/l2cap.h>
 #include <net/bluetooth/a2mp.h>
 
+/* A2MP build & send command helper functions */
+static struct a2mp_cmd *__a2mp_build(u8 code, u8 ident, u16 len, void *data)
+{
+	struct a2mp_cmd *cmd;
+	int plen;
+
+	plen = sizeof(*cmd) + len;
+	cmd = kzalloc(plen, GFP_KERNEL);
+	if (!cmd)
+		return NULL;
+
+	cmd->code = code;
+	cmd->ident = ident;
+	cmd->len = cpu_to_le16(len);
+
+	memcpy(cmd->data, data, len);
+
+	return cmd;
+}
+
+static void a2mp_send(struct amp_mgr *mgr, u8 code, u8 ident, u16 len,
+		      void *data)
+{
+	struct l2cap_chan *chan = mgr->a2mp_chan;
+	struct a2mp_cmd *cmd;
+	u16 total_len = len + sizeof(*cmd);
+	struct kvec iv;
+	struct msghdr msg;
+
+	cmd = __a2mp_build(code, ident, len, data);
+	if (!cmd)
+		return;
+
+	iv.iov_base = cmd;
+	iv.iov_len = total_len;
+
+	memset(&msg, 0, sizeof(msg));
+
+	msg.msg_iov = (struct iovec *) &iv;
+	msg.msg_iovlen = 1;
+
+	l2cap_chan_send(chan, &msg, total_len, 0);
+
+	kfree(cmd);
+}
+
 static struct l2cap_ops a2mp_chan_ops = {
 	.name = "L2CAP A2MP channel",
 };
-- 
1.7.9.5


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

* [PATCHv2 06/19] Bluetooth: A2MP: Add chan callbacks
  2012-05-23 15:37 ` [PATCHv2 00/19] " Andrei Emeltchenko
                     ` (4 preceding siblings ...)
  2012-05-23 15:37   ` [PATCHv2 05/19] Bluetooth: A2MP: Build and Send msg helpers Andrei Emeltchenko
@ 2012-05-23 15:37   ` Andrei Emeltchenko
  2012-05-23 15:37   ` [PATCHv2 07/19] Bluetooth: A2MP: Definitions for A2MP commands Andrei Emeltchenko
                     ` (12 subsequent siblings)
  18 siblings, 0 replies; 104+ messages in thread
From: Andrei Emeltchenko @ 2012-05-23 15:37 UTC (permalink / raw)
  To: linux-bluetooth

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

Add state change, close and skb allocation callbacks.

Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
 net/bluetooth/a2mp.c |   40 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 40 insertions(+)

diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c
index e7e5f5f..eb98541 100644
--- a/net/bluetooth/a2mp.c
+++ b/net/bluetooth/a2mp.c
@@ -63,8 +63,46 @@ static void a2mp_send(struct amp_mgr *mgr, u8 code, u8 ident, u16 len,
 	kfree(cmd);
 }
 
+static void a2mp_chan_state_change_cb(void *data, int state)
+{
+	struct amp_mgr *mgr = data;
+	struct l2cap_chan *chan;
+
+	if (!mgr)
+		return;
+
+	chan = mgr->a2mp_chan;
+
+	BT_DBG("chan %p state %s", chan, state_to_string(state));
+
+	chan->state = state;
+
+	switch (state) {
+	case BT_CLOSED:
+		if (mgr)
+			amp_mgr_put(mgr);
+		break;
+	}
+}
+
+static void a2mp_chan_close_cb(void *data)
+{
+	struct amp_mgr *mgr = data;
+
+	l2cap_chan_destroy(mgr->a2mp_chan);
+}
+
+static struct sk_buff *a2mp_chan_alloc_skb_cb(struct l2cap_chan *chan,
+					      unsigned long len, int nb)
+{
+	return bt_skb_alloc(len, GFP_KERNEL);
+}
+
 static struct l2cap_ops a2mp_chan_ops = {
 	.name = "L2CAP A2MP channel",
+	.state_change = a2mp_chan_state_change_cb,
+	.close = a2mp_chan_close_cb,
+	.alloc_skb = a2mp_chan_alloc_skb_cb,
 };
 
 static struct l2cap_chan *a2mp_chan_open(struct l2cap_conn *conn)
@@ -110,6 +148,8 @@ static struct l2cap_chan *a2mp_chan_open(struct l2cap_conn *conn)
 	chan->remote_mps = chan->omtu;
 	chan->mps = chan->omtu;
 
+	chan->state = BT_CONNECTED;
+
 	return chan;
 }
 
-- 
1.7.9.5


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

* [PATCHv2 07/19] Bluetooth: A2MP: Definitions for A2MP commands
  2012-05-23 15:37 ` [PATCHv2 00/19] " Andrei Emeltchenko
                     ` (5 preceding siblings ...)
  2012-05-23 15:37   ` [PATCHv2 06/19] Bluetooth: A2MP: Add chan callbacks Andrei Emeltchenko
@ 2012-05-23 15:37   ` Andrei Emeltchenko
  2012-05-23 15:37   ` [PATCHv2 08/19] Bluetooth: A2MP: Define A2MP status codes Andrei Emeltchenko
                     ` (11 subsequent siblings)
  18 siblings, 0 replies; 104+ messages in thread
From: Andrei Emeltchenko @ 2012-05-23 15:37 UTC (permalink / raw)
  To: linux-bluetooth

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

Define A2MP command IDs and packet structures.

Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
 include/net/bluetooth/a2mp.h |   73 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 73 insertions(+)

diff --git a/include/net/bluetooth/a2mp.h b/include/net/bluetooth/a2mp.h
index 654df60..7cbeb91 100644
--- a/include/net/bluetooth/a2mp.h
+++ b/include/net/bluetooth/a2mp.h
@@ -31,6 +31,79 @@ struct a2mp_cmd {
 	__u8	data[0];
 } __packed;
 
+/* A2MP command codes */
+#define A2MP_COMMAND_REJ         0x01
+struct a2mp_cmd_rej {
+	__le16	reason;
+	__u8	data[0];
+} __packed;
+
+#define A2MP_DISCOVER_REQ        0x02
+struct a2mp_discov_req {
+	__le16	mtu;
+	__le16	ext_feat;
+} __packed;
+
+struct a2mp_cl {
+	__u8	id;
+	__u8	type;
+	__u8	status;
+} __packed;
+
+#define A2MP_DISCOVER_RSP        0x03
+struct a2mp_discov_rsp {
+	__le16     mtu;
+	__le16     ext_feat;
+	struct a2mp_cl cl[0];
+} __packed;
+
+#define A2MP_CHANGE_NOTIFY       0x04
+#define A2MP_CHANGE_RSP          0x05
+
+#define A2MP_GETINFO_REQ         0x06
+struct a2mp_info_req {
+	__u8       id;
+} __packed;
+
+#define A2MP_GETINFO_RSP         0x07
+struct a2mp_info_rsp {
+	__u8	id;
+	__u8	status;
+	__le32	total_bw;
+	__le32	max_bw;
+	__le32	min_latency;
+	__le16	pal_cap;
+	__le16	assoc_size;
+} __packed;
+
+#define A2MP_GETAMPASSOC_REQ     0x08
+struct a2mp_amp_assoc_req {
+	__u8	id;
+} __packed;
+
+#define A2MP_GETAMPASSOC_RSP     0x09
+struct a2mp_amp_assoc_rsp {
+	__u8	id;
+	__u8	status;
+	__u8	amp_assoc[0];
+} __packed;
+
+#define A2MP_CREATEPHYSLINK_REQ  0x0A
+#define A2MP_DISCONNPHYSLINK_REQ 0x0C
+struct a2mp_physlink_req {
+	__u8	local_id;
+	__u8	remote_id;
+	__u8	amp_assoc[0];
+} __packed;
+
+#define A2MP_CREATEPHYSLINK_RSP  0x0B
+#define A2MP_DISCONNPHYSLINK_RSP 0x0D
+struct a2mp_physlink_rsp {
+	__u8	local_id;
+	__u8	remote_id;
+	__u8	status;
+} __packed;
+
 void amp_mgr_get(struct amp_mgr *mgr);
 int amp_mgr_put(struct amp_mgr *mgr);
 
-- 
1.7.9.5


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

* [PATCHv2 08/19] Bluetooth: A2MP: Define A2MP status codes
  2012-05-23 15:37 ` [PATCHv2 00/19] " Andrei Emeltchenko
                     ` (6 preceding siblings ...)
  2012-05-23 15:37   ` [PATCHv2 07/19] Bluetooth: A2MP: Definitions for A2MP commands Andrei Emeltchenko
@ 2012-05-23 15:37   ` Andrei Emeltchenko
  2012-05-23 15:37   ` [PATCHv2 09/19] Bluetooth: A2MP: Process A2MP messages Andrei Emeltchenko
                     ` (10 subsequent siblings)
  18 siblings, 0 replies; 104+ messages in thread
From: Andrei Emeltchenko @ 2012-05-23 15:37 UTC (permalink / raw)
  To: linux-bluetooth

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

A2MP status codes copied from Bluez patch sent by Peter Krystad
<pkrystad@codeaurora.org>.

Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
 include/net/bluetooth/a2mp.h |   10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/include/net/bluetooth/a2mp.h b/include/net/bluetooth/a2mp.h
index 7cbeb91..391acd7 100644
--- a/include/net/bluetooth/a2mp.h
+++ b/include/net/bluetooth/a2mp.h
@@ -104,6 +104,16 @@ struct a2mp_physlink_rsp {
 	__u8	status;
 } __packed;
 
+/* A2MP response status */
+#define A2MP_STATUS_SUCCESS			0x00
+#define A2MP_STATUS_INVALID_CTRL_ID		0x01
+#define A2MP_STATUS_UNABLE_START_LINK_CREATION	0x02
+#define A2MP_STATUS_NO_PHYSICAL_LINK_EXISTS	0x02
+#define A2MP_STATUS_COLLISION_OCCURED		0x03
+#define A2MP_STATUS_DISCONN_REQ_RECVD		0x04
+#define A2MP_STATUS_PHYS_LINK_EXISTS		0x05
+#define A2MP_STATUS_SECURITY_VIOLATION		0x06
+
 void amp_mgr_get(struct amp_mgr *mgr);
 int amp_mgr_put(struct amp_mgr *mgr);
 
-- 
1.7.9.5


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

* [PATCHv2 09/19] Bluetooth: A2MP: Process A2MP messages
  2012-05-23 15:37 ` [PATCHv2 00/19] " Andrei Emeltchenko
                     ` (7 preceding siblings ...)
  2012-05-23 15:37   ` [PATCHv2 08/19] Bluetooth: A2MP: Define A2MP status codes Andrei Emeltchenko
@ 2012-05-23 15:37   ` Andrei Emeltchenko
  2012-05-23 15:37   ` [PATCHv2 10/19] Bluetooth: A2MP: Process A2MP Command Reject Andrei Emeltchenko
                     ` (9 subsequent siblings)
  18 siblings, 0 replies; 104+ messages in thread
From: Andrei Emeltchenko @ 2012-05-23 15:37 UTC (permalink / raw)
  To: linux-bluetooth

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

Implement basic processing for AMP Manager Protocol (A2MP).

Example below shows processing unrecognized command.
...
> ACL data: handle 11 flags 0x02 dlen 12
    A2MP: code 0x00 ident 3 len 0
< ACL data: handle 11 flags 0x00 dlen 14
    A2MP: Command Reject: reason (0) - Command not recognized
...

Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
 net/bluetooth/a2mp.c |   65 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 65 insertions(+)

diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c
index eb98541..92b7671 100644
--- a/net/bluetooth/a2mp.c
+++ b/net/bluetooth/a2mp.c
@@ -63,6 +63,70 @@ static void a2mp_send(struct amp_mgr *mgr, u8 code, u8 ident, u16 len,
 	kfree(cmd);
 }
 
+/* Handle A2MP signalling */
+static int a2mp_chan_recv_cb(void *data, struct sk_buff *skb)
+{
+	struct a2mp_cmd *hdr = (struct a2mp_cmd *) skb->data;
+	struct amp_mgr *mgr = data;
+	int err = 0;
+
+	amp_mgr_get(mgr);
+
+	while (skb->len >= sizeof(*hdr)) {
+		struct a2mp_cmd *hdr = (struct a2mp_cmd *) skb->data;
+		u16 len = le16_to_cpu(hdr->len);
+
+		BT_DBG("code 0x%02x id %d len %d", hdr->code, hdr->ident, len);
+
+		skb_pull(skb, sizeof(*hdr));
+
+		if (len > skb->len || !hdr->ident) {
+			err = -EINVAL;
+			break;
+		}
+
+		mgr->ident = hdr->ident;
+
+		switch (hdr->code) {
+		case A2MP_COMMAND_REJ:
+		case A2MP_DISCOVER_REQ:
+		case A2MP_CHANGE_NOTIFY:
+		case A2MP_GETINFO_REQ:
+		case A2MP_GETAMPASSOC_REQ:
+		case A2MP_CREATEPHYSLINK_REQ:
+		case A2MP_DISCONNPHYSLINK_REQ:
+		case A2MP_CHANGE_RSP:
+		case A2MP_DISCOVER_RSP:
+		case A2MP_GETINFO_RSP:
+		case A2MP_GETAMPASSOC_RSP:
+		case A2MP_CREATEPHYSLINK_RSP:
+		case A2MP_DISCONNPHYSLINK_RSP:
+		default:
+			BT_ERR("Unknown A2MP sig cmd 0x%2.2x", hdr->code);
+			err = -EINVAL;
+			break;
+		}
+	}
+
+	if (err) {
+		struct a2mp_cmd_rej rej;
+		rej.reason = cpu_to_le16(0);
+
+		BT_DBG("Send A2MP Rej: cmd 0x%2.2x err %d", hdr->code, err);
+
+		a2mp_send(mgr, A2MP_COMMAND_REJ, hdr->ident, sizeof(rej),
+			  &rej);
+	}
+
+	/* Always free skb and return success error code to prevent
+	   from sending L2CAP Disconnect over A2MP channel */
+	kfree_skb(skb);
+
+	amp_mgr_put(mgr);
+
+	return 0;
+}
+
 static void a2mp_chan_state_change_cb(void *data, int state)
 {
 	struct amp_mgr *mgr = data;
@@ -100,6 +164,7 @@ static struct sk_buff *a2mp_chan_alloc_skb_cb(struct l2cap_chan *chan,
 
 static struct l2cap_ops a2mp_chan_ops = {
 	.name = "L2CAP A2MP channel",
+	.recv = a2mp_chan_recv_cb,
 	.state_change = a2mp_chan_state_change_cb,
 	.close = a2mp_chan_close_cb,
 	.alloc_skb = a2mp_chan_alloc_skb_cb,
-- 
1.7.9.5


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

* [PATCHv2 10/19] Bluetooth: A2MP: Process A2MP Command Reject
  2012-05-23 15:37 ` [PATCHv2 00/19] " Andrei Emeltchenko
                     ` (8 preceding siblings ...)
  2012-05-23 15:37   ` [PATCHv2 09/19] Bluetooth: A2MP: Process A2MP messages Andrei Emeltchenko
@ 2012-05-23 15:37   ` Andrei Emeltchenko
  2012-05-23 15:37   ` [PATCHv2 11/19] Bluetooth: A2MP: Process A2MP Discover Request Andrei Emeltchenko
                     ` (8 subsequent siblings)
  18 siblings, 0 replies; 104+ messages in thread
From: Andrei Emeltchenko @ 2012-05-23 15:37 UTC (permalink / raw)
  To: linux-bluetooth

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

Placeholder for future A2MP Command Reject handler.

Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
 net/bluetooth/a2mp.c |   19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c
index 92b7671..4137f9b 100644
--- a/net/bluetooth/a2mp.c
+++ b/net/bluetooth/a2mp.c
@@ -63,6 +63,22 @@ static void a2mp_send(struct amp_mgr *mgr, u8 code, u8 ident, u16 len,
 	kfree(cmd);
 }
 
+/* Processing A2MP messages */
+static int a2mp_command_rej(struct amp_mgr *mgr, struct sk_buff *skb,
+			    struct a2mp_cmd *hdr)
+{
+	struct a2mp_cmd_rej *rej = (struct a2mp_cmd_rej *) skb->data;
+
+	if (le16_to_cpu(hdr->len) < sizeof(*rej))
+		return -EINVAL;
+
+	BT_DBG("ident %d reason %d", hdr->ident, le16_to_cpu(rej->reason));
+
+	skb_pull(skb, sizeof(*rej));
+
+	return 0;
+}
+
 /* Handle A2MP signalling */
 static int a2mp_chan_recv_cb(void *data, struct sk_buff *skb)
 {
@@ -89,6 +105,9 @@ static int a2mp_chan_recv_cb(void *data, struct sk_buff *skb)
 
 		switch (hdr->code) {
 		case A2MP_COMMAND_REJ:
+			a2mp_command_rej(mgr, skb, hdr);
+			break;
+
 		case A2MP_DISCOVER_REQ:
 		case A2MP_CHANGE_NOTIFY:
 		case A2MP_GETINFO_REQ:
-- 
1.7.9.5


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

* [PATCHv2 11/19] Bluetooth: A2MP: Process A2MP Discover Request
  2012-05-23 15:37 ` [PATCHv2 00/19] " Andrei Emeltchenko
                     ` (9 preceding siblings ...)
  2012-05-23 15:37   ` [PATCHv2 10/19] Bluetooth: A2MP: Process A2MP Command Reject Andrei Emeltchenko
@ 2012-05-23 15:37   ` Andrei Emeltchenko
  2012-05-23 15:37   ` [PATCHv2 12/19] Bluetooth: A2MP: Process A2MP Change Notify Andrei Emeltchenko
                     ` (7 subsequent siblings)
  18 siblings, 0 replies; 104+ messages in thread
From: Andrei Emeltchenko @ 2012-05-23 15:37 UTC (permalink / raw)
  To: linux-bluetooth

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

Adds helper functions to count HCI devs and process A2MP Discover
Request, code makes sure that first controller in the list is
BREDR one. Trace is shown below:

...
> ACL data: handle 11 flags 0x02 dlen 16
    A2MP: Discover req: mtu/mps 670 mask: 0x0000
< ACL data: handle 11 flags 0x00 dlen 22
    A2MP: Discover rsp: mtu/mps 670 mask: 0x0000
      Controller list:
        id 0 type 0 (BR-EDR) status 0x01 (Bluetooth only)
        id 1 type 1 (802.11 AMP) status 0x01 (Bluetooth only)
...

Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
 include/net/bluetooth/a2mp.h     |    2 +
 include/net/bluetooth/hci.h      |    3 ++
 include/net/bluetooth/hci_core.h |   13 ++++++
 net/bluetooth/a2mp.c             |   85 ++++++++++++++++++++++++++++++++++++++
 4 files changed, 103 insertions(+)

diff --git a/include/net/bluetooth/a2mp.h b/include/net/bluetooth/a2mp.h
index 391acd7..96f9cc2 100644
--- a/include/net/bluetooth/a2mp.h
+++ b/include/net/bluetooth/a2mp.h
@@ -15,6 +15,8 @@
 #ifndef __A2MP_H
 #define __A2MP_H
 
+#define A2MP_FEAT_EXT	0x8000
+
 struct amp_mgr {
 	struct l2cap_conn	*l2cap_conn;
 	struct l2cap_chan	*a2mp_chan;
diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index edb6639..158f403 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -58,6 +58,9 @@
 #define HCI_BREDR	0x00
 #define HCI_AMP		0x01
 
+/* First BR/EDR Controller shall have ID = 0 */
+#define HCI_BREDR_ID	0
+
 /* HCI device quirks */
 enum {
 	HCI_QUIRK_RESET_ON_CLOSE,
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 6e64b76..20fd573 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -641,6 +641,19 @@ static inline void hci_set_drvdata(struct hci_dev *hdev, void *data)
 	dev_set_drvdata(&hdev->dev, data);
 }
 
+/* hci_dev_list shall be locked */
+static inline uint8_t __hci_num_ctrl(void)
+{
+	uint8_t count = 0;
+	struct list_head *p;
+
+	list_for_each(p, &hci_dev_list) {
+		count++;
+	}
+
+	return count;
+}
+
 struct hci_dev *hci_dev_get(int index);
 struct hci_dev *hci_get_route(bdaddr_t *src, bdaddr_t *dst);
 
diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c
index 4137f9b..ac095ac 100644
--- a/net/bluetooth/a2mp.c
+++ b/net/bluetooth/a2mp.c
@@ -63,6 +63,36 @@ static void a2mp_send(struct amp_mgr *mgr, u8 code, u8 ident, u16 len,
 	kfree(cmd);
 }
 
+static inline void __a2mp_cl_bredr(struct a2mp_cl *cl)
+{
+	cl->id = 0;
+	cl->type = 0;
+	cl->status = 1;
+}
+
+/* hci_dev_list shall be locked */
+static void __a2mp_add_cl(struct amp_mgr *mgr, struct a2mp_cl *cl, u8 num_ctrl)
+{
+	int i = 0;
+	struct hci_dev *hdev;
+
+	__a2mp_cl_bredr(cl);
+
+	list_for_each_entry(hdev, &hci_dev_list, list) {
+		/* Iterate through AMP controllers */
+		if (hdev->id == HCI_BREDR_ID)
+			continue;
+
+		/* Starting from second entry */
+		if (++i >= num_ctrl)
+			return;
+
+		cl[i].id = hdev->id;
+		cl[i].type = hdev->amp_type;
+		cl[i].status = hdev->amp_status;
+	}
+}
+
 /* Processing A2MP messages */
 static int a2mp_command_rej(struct amp_mgr *mgr, struct sk_buff *skb,
 			    struct a2mp_cmd *hdr)
@@ -79,6 +109,58 @@ static int a2mp_command_rej(struct amp_mgr *mgr, struct sk_buff *skb,
 	return 0;
 }
 
+static int a2mp_discover_req(struct amp_mgr *mgr, struct sk_buff *skb,
+			     struct a2mp_cmd *hdr)
+{
+	struct a2mp_discov_req *req = (struct a2mp_discov_req *) skb->data;
+	u16 len = le16_to_cpu(hdr->len);
+	struct a2mp_discov_rsp *rsp;
+	u16 ext_feat;
+	u8 num_ctrl;
+
+	if (len < sizeof(*req))
+		return -EINVAL;
+
+	skb_pull(skb, sizeof(*req));
+
+	ext_feat = le16_to_cpu(req->ext_feat);
+
+	BT_DBG("mtu %d efm 0x%4.4x", le16_to_cpu(req->mtu), ext_feat);
+
+	/* check that packet is not broken for now */
+	while (ext_feat & A2MP_FEAT_EXT) {
+		if (len < sizeof(ext_feat))
+			return -EINVAL;
+
+		ext_feat = get_unaligned_le16(skb->data);
+		BT_DBG("efm 0x%4.4x", ext_feat);
+		len -= sizeof(ext_feat);
+		skb_pull(skb, sizeof(ext_feat));
+	}
+
+	read_lock(&hci_dev_list_lock);
+
+	num_ctrl = __hci_num_ctrl();
+	len = num_ctrl * sizeof(struct a2mp_cl) + sizeof(*rsp);
+	rsp = kmalloc(len, GFP_ATOMIC);
+	if (!rsp) {
+		read_unlock(&hci_dev_list_lock);
+		return -ENOMEM;
+	}
+
+	rsp->mtu = cpu_to_le16(L2CAP_A2MP_DEFAULT_MTU);
+	rsp->ext_feat = 0;
+
+	__a2mp_add_cl(mgr, rsp->cl, num_ctrl);
+
+	read_unlock(&hci_dev_list_lock);
+
+	a2mp_send(mgr, A2MP_DISCOVER_RSP, hdr->ident, len, rsp);
+
+	kfree(rsp);
+	return 0;
+}
+
 /* Handle A2MP signalling */
 static int a2mp_chan_recv_cb(void *data, struct sk_buff *skb)
 {
@@ -109,6 +191,9 @@ static int a2mp_chan_recv_cb(void *data, struct sk_buff *skb)
 			break;
 
 		case A2MP_DISCOVER_REQ:
+			err = a2mp_discover_req(mgr, skb, hdr);
+			break;
+
 		case A2MP_CHANGE_NOTIFY:
 		case A2MP_GETINFO_REQ:
 		case A2MP_GETAMPASSOC_REQ:
-- 
1.7.9.5


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

* [PATCHv2 12/19] Bluetooth: A2MP: Process A2MP Change Notify
  2012-05-23 15:37 ` [PATCHv2 00/19] " Andrei Emeltchenko
                     ` (10 preceding siblings ...)
  2012-05-23 15:37   ` [PATCHv2 11/19] Bluetooth: A2MP: Process A2MP Discover Request Andrei Emeltchenko
@ 2012-05-23 15:37   ` Andrei Emeltchenko
  2012-05-23 15:37   ` [PATCHv2 13/19] Bluetooth: A2MP: Process A2MP Get Info Request Andrei Emeltchenko
                     ` (6 subsequent siblings)
  18 siblings, 0 replies; 104+ messages in thread
From: Andrei Emeltchenko @ 2012-05-23 15:37 UTC (permalink / raw)
  To: linux-bluetooth

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

Placeholder for A2MP Change Notify handler.

Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
 net/bluetooth/a2mp.c |   19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c
index ac095ac..d60be75 100644
--- a/net/bluetooth/a2mp.c
+++ b/net/bluetooth/a2mp.c
@@ -161,6 +161,22 @@ static int a2mp_discover_req(struct amp_mgr *mgr, struct sk_buff *skb,
 	return 0;
 }
 
+static int a2mp_change_notify(struct amp_mgr *mgr, struct sk_buff *skb,
+			      struct a2mp_cmd *hdr)
+{
+	struct a2mp_cl *cl = (struct a2mp_cl *) skb->data;
+
+	while (skb->len >= sizeof(*cl)) {
+		BT_DBG("Controller id %d type %d status %d", cl->id, cl->type,
+		       cl->status);
+		cl = (struct a2mp_cl *) skb_pull(skb, sizeof(*cl));
+	}
+
+	/* TODO send A2MP_CHANGE_RSP */
+
+	return 0;
+}
+
 /* Handle A2MP signalling */
 static int a2mp_chan_recv_cb(void *data, struct sk_buff *skb)
 {
@@ -195,6 +211,9 @@ static int a2mp_chan_recv_cb(void *data, struct sk_buff *skb)
 			break;
 
 		case A2MP_CHANGE_NOTIFY:
+			err = a2mp_change_notify(mgr, skb, hdr);
+			break;
+
 		case A2MP_GETINFO_REQ:
 		case A2MP_GETAMPASSOC_REQ:
 		case A2MP_CREATEPHYSLINK_REQ:
-- 
1.7.9.5


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

* [PATCHv2 13/19] Bluetooth: A2MP: Process A2MP Get Info Request
  2012-05-23 15:37 ` [PATCHv2 00/19] " Andrei Emeltchenko
                     ` (11 preceding siblings ...)
  2012-05-23 15:37   ` [PATCHv2 12/19] Bluetooth: A2MP: Process A2MP Change Notify Andrei Emeltchenko
@ 2012-05-23 15:37   ` Andrei Emeltchenko
  2012-05-23 15:37   ` [PATCHv2 14/19] Bluetooth: A2MP: Process A2MP Get AMP Assoc Request Andrei Emeltchenko
                     ` (5 subsequent siblings)
  18 siblings, 0 replies; 104+ messages in thread
From: Andrei Emeltchenko @ 2012-05-23 15:37 UTC (permalink / raw)
  To: linux-bluetooth

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

Process A2MP Get Info Request.
Example of trace log for invalid controller id is shown below:

...
> ACL data: handle 11 flags 0x02 dlen 13
    A2MP: Get Info req: id 238
< ACL data: handle 11 flags 0x00 dlen 30
    A2MP: Get Info rsp: id 238 status (1) Invalid Controller ID
...

Note that If the Status field is set to Invalid Controller ID all subsequent
fields in the AMP Get Info Response shall be ignored by the receiver.

Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
 net/bluetooth/a2mp.c |   37 +++++++++++++++++++++++++++++++++++++
 1 file changed, 37 insertions(+)

diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c
index d60be75..d636c0c 100644
--- a/net/bluetooth/a2mp.c
+++ b/net/bluetooth/a2mp.c
@@ -177,6 +177,40 @@ static int a2mp_change_notify(struct amp_mgr *mgr, struct sk_buff *skb,
 	return 0;
 }
 
+static int a2mp_getinfo_req(struct amp_mgr *mgr, struct sk_buff *skb,
+			    struct a2mp_cmd *hdr)
+{
+	struct a2mp_info_req *req  = (struct a2mp_info_req *) skb->data;
+	struct a2mp_info_rsp rsp;
+	struct hci_dev *hdev;
+
+	if (le16_to_cpu(hdr->len) < sizeof(*req))
+		return -EINVAL;
+
+	BT_DBG("id %d", req->id);
+
+	rsp.id = req->id;
+	rsp.status = A2MP_STATUS_INVALID_CTRL_ID;
+
+	hdev = hci_dev_get(req->id);
+	if (hdev && hdev->amp_type != HCI_BREDR) {
+		rsp.status = 0;
+		rsp.total_bw = cpu_to_le32(hdev->amp_total_bw);
+		rsp.max_bw = cpu_to_le32(hdev->amp_max_bw);
+		rsp.min_latency = cpu_to_le32(hdev->amp_min_latency);
+		rsp.pal_cap = cpu_to_le16(hdev->amp_pal_cap);
+		rsp.assoc_size = cpu_to_le16(hdev->amp_assoc_size);
+	}
+
+	if (hdev)
+		hci_dev_put(hdev);
+
+	a2mp_send(mgr, A2MP_GETINFO_RSP, hdr->ident, sizeof(rsp), &rsp);
+
+	skb_pull(skb, sizeof(*req));
+	return 0;
+}
+
 /* Handle A2MP signalling */
 static int a2mp_chan_recv_cb(void *data, struct sk_buff *skb)
 {
@@ -215,6 +249,9 @@ static int a2mp_chan_recv_cb(void *data, struct sk_buff *skb)
 			break;
 
 		case A2MP_GETINFO_REQ:
+			err = a2mp_getinfo_req(mgr, skb, hdr);
+			break;
+
 		case A2MP_GETAMPASSOC_REQ:
 		case A2MP_CREATEPHYSLINK_REQ:
 		case A2MP_DISCONNPHYSLINK_REQ:
-- 
1.7.9.5


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

* [PATCHv2 14/19] Bluetooth: A2MP: Process A2MP Get AMP Assoc Request
  2012-05-23 15:37 ` [PATCHv2 00/19] " Andrei Emeltchenko
                     ` (12 preceding siblings ...)
  2012-05-23 15:37   ` [PATCHv2 13/19] Bluetooth: A2MP: Process A2MP Get Info Request Andrei Emeltchenko
@ 2012-05-23 15:37   ` Andrei Emeltchenko
  2012-05-23 15:37   ` [PATCHv2 15/19] Bluetooth: A2MP: Process A2MP Create Physlink Request Andrei Emeltchenko
                     ` (4 subsequent siblings)
  18 siblings, 0 replies; 104+ messages in thread
From: Andrei Emeltchenko @ 2012-05-23 15:37 UTC (permalink / raw)
  To: linux-bluetooth

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

Example trace when receiving AMP Assoc Request with wrong AMP id.
...
> ACL data: handle 11 flags 0x02 dlen 13
    A2MP: Get AMP Assoc req: id 238
< ACL data: handle 11 flags 0x00 dlen 14
    A2MP: Get AMP Assoc rsp: id 238 status (1) Invalid Controller ID
      assoc data:
...

Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
 net/bluetooth/a2mp.c |   36 ++++++++++++++++++++++++++++++++++++
 1 file changed, 36 insertions(+)

diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c
index d636c0c..c98a402 100644
--- a/net/bluetooth/a2mp.c
+++ b/net/bluetooth/a2mp.c
@@ -211,6 +211,39 @@ static int a2mp_getinfo_req(struct amp_mgr *mgr, struct sk_buff *skb,
 	return 0;
 }
 
+static int a2mp_getampassoc_req(struct amp_mgr *mgr, struct sk_buff *skb,
+				struct a2mp_cmd *hdr)
+{
+	struct a2mp_amp_assoc_req *req =
+				(struct a2mp_amp_assoc_req *) skb->data;
+	struct hci_dev *hdev;
+
+	if (le16_to_cpu(hdr->len) < sizeof(*req))
+		return -EINVAL;
+
+	BT_DBG("id %d", req->id);
+
+	hdev = hci_dev_get(req->id);
+	if (!hdev || hdev->amp_type == HCI_BREDR) {
+		struct a2mp_amp_assoc_rsp rsp;
+		rsp.id = req->id;
+		rsp.status = A2MP_STATUS_INVALID_CTRL_ID;
+
+		a2mp_send(mgr, A2MP_GETAMPASSOC_RSP, hdr->ident, sizeof(rsp),
+			  &rsp);
+		goto clean;
+	}
+
+	/* Placeholder for HCI Read AMP Assoc */
+
+clean:
+	if (hdev)
+		hci_dev_put(hdev);
+
+	skb_pull(skb, sizeof(*req));
+	return 0;
+}
+
 /* Handle A2MP signalling */
 static int a2mp_chan_recv_cb(void *data, struct sk_buff *skb)
 {
@@ -253,6 +286,9 @@ static int a2mp_chan_recv_cb(void *data, struct sk_buff *skb)
 			break;
 
 		case A2MP_GETAMPASSOC_REQ:
+			err = a2mp_getampassoc_req(mgr, skb, hdr);
+			break;
+
 		case A2MP_CREATEPHYSLINK_REQ:
 		case A2MP_DISCONNPHYSLINK_REQ:
 		case A2MP_CHANGE_RSP:
-- 
1.7.9.5


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

* [PATCHv2 15/19] Bluetooth: A2MP: Process A2MP Create Physlink Request
  2012-05-23 15:37 ` [PATCHv2 00/19] " Andrei Emeltchenko
                     ` (13 preceding siblings ...)
  2012-05-23 15:37   ` [PATCHv2 14/19] Bluetooth: A2MP: Process A2MP Get AMP Assoc Request Andrei Emeltchenko
@ 2012-05-23 15:37   ` Andrei Emeltchenko
  2012-05-23 15:37   ` [PATCHv2 16/19] Bluetooth: A2MP: Process A2MP Disc " Andrei Emeltchenko
                     ` (3 subsequent siblings)
  18 siblings, 0 replies; 104+ messages in thread
From: Andrei Emeltchenko @ 2012-05-23 15:37 UTC (permalink / raw)
  To: linux-bluetooth

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

Placeholder for A2MP Create Physlink Request.
Handles requests with invalid controler id as shown below:

...
> ACL data: handle 11 flags 0x02 dlen 50
    A2MP: Create Physical Link req: local id 1 remote id 85
      Assoc data:
        <skipped>
< ACL data: handle 11 flags 0x00 dlen 15
    A2MP: Create Physical Link rsp: local id 85 remote id 1 status 1
      Invalid Controller ID
...

Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
 net/bluetooth/a2mp.c |   39 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 39 insertions(+)

diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c
index c98a402..ae4e38b 100644
--- a/net/bluetooth/a2mp.c
+++ b/net/bluetooth/a2mp.c
@@ -244,6 +244,42 @@ clean:
 	return 0;
 }
 
+static int a2mp_createphyslink_req(struct amp_mgr *mgr, struct sk_buff *skb,
+				   struct a2mp_cmd *hdr)
+{
+	struct a2mp_physlink_req *req = (struct a2mp_physlink_req *) skb->data;
+	struct a2mp_physlink_rsp rsp;
+	struct hci_dev *hdev;
+
+	if (le16_to_cpu(hdr->len) < sizeof(*req))
+		return -EINVAL;
+
+	BT_DBG("local_id %d, remote_id %d", req->local_id, req->remote_id);
+
+	rsp.local_id = req->remote_id;
+	rsp.remote_id = req->local_id;
+
+	hdev = hci_dev_get(req->remote_id);
+	if (!hdev || hdev->amp_type != HCI_AMP) {
+		rsp.status = A2MP_STATUS_INVALID_CTRL_ID;
+		goto send_rsp;
+	}
+
+	/* TODO process physlink create */
+
+	rsp.status = A2MP_STATUS_SUCCESS;
+
+send_rsp:
+	if (hdev)
+		hci_dev_put(hdev);
+
+	a2mp_send(mgr, A2MP_CREATEPHYSLINK_RSP, hdr->ident, sizeof(rsp),
+		  &rsp);
+
+	skb_pull(skb, le16_to_cpu(hdr->len));
+	return 0;
+}
+
 /* Handle A2MP signalling */
 static int a2mp_chan_recv_cb(void *data, struct sk_buff *skb)
 {
@@ -290,6 +326,9 @@ static int a2mp_chan_recv_cb(void *data, struct sk_buff *skb)
 			break;
 
 		case A2MP_CREATEPHYSLINK_REQ:
+			err = a2mp_createphyslink_req(mgr, skb, hdr);
+			break;
+
 		case A2MP_DISCONNPHYSLINK_REQ:
 		case A2MP_CHANGE_RSP:
 		case A2MP_DISCOVER_RSP:
-- 
1.7.9.5


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

* [PATCHv2 16/19] Bluetooth: A2MP: Process A2MP Disc Physlink Request
  2012-05-23 15:37 ` [PATCHv2 00/19] " Andrei Emeltchenko
                     ` (14 preceding siblings ...)
  2012-05-23 15:37   ` [PATCHv2 15/19] Bluetooth: A2MP: Process A2MP Create Physlink Request Andrei Emeltchenko
@ 2012-05-23 15:37   ` Andrei Emeltchenko
  2012-05-23 15:37   ` [PATCHv2 17/19] Bluetooth: A2MP: Process A2MP Command Responses Andrei Emeltchenko
                     ` (2 subsequent siblings)
  18 siblings, 0 replies; 104+ messages in thread
From: Andrei Emeltchenko @ 2012-05-23 15:37 UTC (permalink / raw)
  To: linux-bluetooth

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

Placeholder for A2MP Disconnect Physlink Request.

Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
 net/bluetooth/a2mp.c |   36 ++++++++++++++++++++++++++++++++++++
 1 file changed, 36 insertions(+)

diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c
index ae4e38b..16598f9 100644
--- a/net/bluetooth/a2mp.c
+++ b/net/bluetooth/a2mp.c
@@ -280,6 +280,39 @@ send_rsp:
 	return 0;
 }
 
+static int a2mp_discphyslink_req(struct amp_mgr *mgr, struct sk_buff *skb,
+				 struct a2mp_cmd *hdr)
+{
+	struct a2mp_physlink_req *req = (struct a2mp_physlink_req *) skb->data;
+	struct a2mp_physlink_rsp rsp;
+	struct hci_dev *hdev;
+
+	if (le16_to_cpu(hdr->len) < sizeof(*req))
+		return -EINVAL;
+
+	BT_DBG("local_id %d remote_id %d", req->local_id, req->remote_id);
+
+	rsp.local_id = req->remote_id;
+	rsp.remote_id = req->local_id;
+	rsp.status = A2MP_STATUS_SUCCESS;
+
+	hdev = hci_dev_get(req->local_id);
+	if (!hdev) {
+		rsp.status = A2MP_STATUS_INVALID_CTRL_ID;
+		goto send_rsp;
+	}
+
+	/* TODO Disconnect Phys Link here */
+
+	hci_dev_put(hdev);
+
+send_rsp:
+	a2mp_send(mgr, A2MP_DISCONNPHYSLINK_RSP, hdr->ident, sizeof(rsp), &rsp);
+
+	skb_pull(skb, sizeof(*req));
+	return 0;
+}
+
 /* Handle A2MP signalling */
 static int a2mp_chan_recv_cb(void *data, struct sk_buff *skb)
 {
@@ -330,6 +363,9 @@ static int a2mp_chan_recv_cb(void *data, struct sk_buff *skb)
 			break;
 
 		case A2MP_DISCONNPHYSLINK_REQ:
+			err = a2mp_discphyslink_req(mgr, skb, hdr);
+			break;
+
 		case A2MP_CHANGE_RSP:
 		case A2MP_DISCOVER_RSP:
 		case A2MP_GETINFO_RSP:
-- 
1.7.9.5


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

* [PATCHv2 17/19] Bluetooth: A2MP: Process A2MP Command Responses
  2012-05-23 15:37 ` [PATCHv2 00/19] " Andrei Emeltchenko
                     ` (15 preceding siblings ...)
  2012-05-23 15:37   ` [PATCHv2 16/19] Bluetooth: A2MP: Process A2MP Disc " Andrei Emeltchenko
@ 2012-05-23 15:37   ` Andrei Emeltchenko
  2012-05-23 15:37   ` [PATCHv2 18/19] Bluetooth: A2MP: Handling fixed channels Andrei Emeltchenko
  2012-05-23 15:37   ` [PATCHv2 19/19] Bluetooth: A2MP: Manage incoming connections Andrei Emeltchenko
  18 siblings, 0 replies; 104+ messages in thread
From: Andrei Emeltchenko @ 2012-05-23 15:37 UTC (permalink / raw)
  To: linux-bluetooth

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

Process A2MP responses, print cmd code and ident for now.

Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
 net/bluetooth/a2mp.c |   12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c
index 16598f9..a454f8b 100644
--- a/net/bluetooth/a2mp.c
+++ b/net/bluetooth/a2mp.c
@@ -313,6 +313,15 @@ send_rsp:
 	return 0;
 }
 
+static inline int a2mp_cmd_rsp(struct amp_mgr *mgr, struct sk_buff *skb,
+			       struct a2mp_cmd *hdr)
+{
+	BT_DBG("ident %d code %d", hdr->ident, hdr->code);
+
+	skb_pull(skb, le16_to_cpu(hdr->len));
+	return 0;
+}
+
 /* Handle A2MP signalling */
 static int a2mp_chan_recv_cb(void *data, struct sk_buff *skb)
 {
@@ -372,6 +381,9 @@ static int a2mp_chan_recv_cb(void *data, struct sk_buff *skb)
 		case A2MP_GETAMPASSOC_RSP:
 		case A2MP_CREATEPHYSLINK_RSP:
 		case A2MP_DISCONNPHYSLINK_RSP:
+			err = a2mp_cmd_rsp(mgr, skb, hdr);
+			break;
+
 		default:
 			BT_ERR("Unknown A2MP sig cmd 0x%2.2x", hdr->code);
 			err = -EINVAL;
-- 
1.7.9.5


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

* [PATCHv2 18/19] Bluetooth: A2MP: Handling fixed channels
  2012-05-23 15:37 ` [PATCHv2 00/19] " Andrei Emeltchenko
                     ` (16 preceding siblings ...)
  2012-05-23 15:37   ` [PATCHv2 17/19] Bluetooth: A2MP: Process A2MP Command Responses Andrei Emeltchenko
@ 2012-05-23 15:37   ` Andrei Emeltchenko
  2012-05-23 15:37   ` [PATCHv2 19/19] Bluetooth: A2MP: Manage incoming connections Andrei Emeltchenko
  18 siblings, 0 replies; 104+ messages in thread
From: Andrei Emeltchenko @ 2012-05-23 15:37 UTC (permalink / raw)
  To: linux-bluetooth

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

A2MP fixed channel do not have sk

Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
 include/net/bluetooth/l2cap.h |    1 +
 net/bluetooth/a2mp.c          |    3 +--
 net/bluetooth/l2cap_core.c    |   17 +++++++++++++++++
 3 files changed, 19 insertions(+), 2 deletions(-)

diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index b022329..2fd0afd 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -575,6 +575,7 @@ struct l2cap_conn {
 #define L2CAP_CHAN_RAW			1
 #define L2CAP_CHAN_CONN_LESS		2
 #define L2CAP_CHAN_CONN_ORIENTED	3
+#define L2CAP_CHAN_CONN_FIX_A2MP	4
 
 /* ----- L2CAP socket info ----- */
 #define l2cap_pi(sk) ((struct l2cap_pinfo *) sk)
diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c
index a454f8b..894e53c 100644
--- a/net/bluetooth/a2mp.c
+++ b/net/bluetooth/a2mp.c
@@ -466,8 +466,7 @@ static struct l2cap_chan *a2mp_chan_open(struct l2cap_conn *conn)
 
 	hci_conn_hold(conn->hcon);
 
-	chan->omtu = L2CAP_A2MP_DEFAULT_MTU;
-	chan->imtu = L2CAP_A2MP_DEFAULT_MTU;
+	chan->chan_type = L2CAP_CHAN_CONN_FIX_A2MP;
 	chan->flush_to = L2CAP_DEFAULT_FLUSH_TO;
 
 	chan->ops = &a2mp_chan_ops;
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 988ee09..bd9197c 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -465,6 +465,13 @@ static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
 		chan->omtu = L2CAP_DEFAULT_MTU;
 		break;
 
+	case L2CAP_CHAN_CONN_FIX_A2MP:
+		chan->scid = L2CAP_CID_A2MP;
+		chan->dcid = L2CAP_CID_A2MP;
+		chan->omtu = L2CAP_A2MP_DEFAULT_MTU;
+		chan->imtu = L2CAP_A2MP_DEFAULT_MTU;
+		break;
+
 	default:
 		/* Raw socket can send/recv signalling messages only */
 		chan->scid = L2CAP_CID_SIGNALING;
@@ -1014,6 +1021,11 @@ static void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *c
 		__clear_ack_timer(chan);
 	}
 
+	if (chan->chan_type == L2CAP_CHAN_CONN_FIX_A2MP) {
+		__l2cap_state_change(chan, BT_DISCONN);
+		return;
+	}
+
 	req.dcid = cpu_to_le16(chan->dcid);
 	req.scid = cpu_to_le16(chan->scid);
 	l2cap_send_cmd(conn, l2cap_get_ident(conn),
@@ -1217,6 +1229,11 @@ static void l2cap_conn_ready(struct l2cap_conn *conn)
 
 		l2cap_chan_lock(chan);
 
+		if (chan->chan_type == L2CAP_CHAN_CONN_FIX_A2MP) {
+			l2cap_chan_unlock(chan);
+			continue;
+		}
+
 		if (conn->hcon->type == LE_LINK) {
 			if (smp_conn_security(conn, chan->sec_level))
 				if (chan->ops->ready)
-- 
1.7.9.5


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

* [PATCHv2 19/19] Bluetooth: A2MP: Manage incoming connections
  2012-05-23 15:37 ` [PATCHv2 00/19] " Andrei Emeltchenko
                     ` (17 preceding siblings ...)
  2012-05-23 15:37   ` [PATCHv2 18/19] Bluetooth: A2MP: Handling fixed channels Andrei Emeltchenko
@ 2012-05-23 15:37   ` Andrei Emeltchenko
  2012-05-23 23:30     ` Mat Martineau
  18 siblings, 1 reply; 104+ messages in thread
From: Andrei Emeltchenko @ 2012-05-23 15:37 UTC (permalink / raw)
  To: linux-bluetooth

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

Handle incoming A2MP connection by creating AMP manager and
processing A2MP messages.

Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
 include/net/bluetooth/a2mp.h |    4 ++++
 net/bluetooth/a2mp.c         |   12 ++++++++++++
 net/bluetooth/l2cap_core.c   |   14 ++++++++++----
 3 files changed, 26 insertions(+), 4 deletions(-)

diff --git a/include/net/bluetooth/a2mp.h b/include/net/bluetooth/a2mp.h
index 96f9cc2..6a76e0a 100644
--- a/include/net/bluetooth/a2mp.h
+++ b/include/net/bluetooth/a2mp.h
@@ -15,6 +15,8 @@
 #ifndef __A2MP_H
 #define __A2MP_H
 
+#include <net/bluetooth/l2cap.h>
+
 #define A2MP_FEAT_EXT	0x8000
 
 struct amp_mgr {
@@ -118,5 +120,7 @@ struct a2mp_physlink_rsp {
 
 void amp_mgr_get(struct amp_mgr *mgr);
 int amp_mgr_put(struct amp_mgr *mgr);
+struct l2cap_chan *a2mp_channel_create(struct l2cap_conn *conn,
+				       struct sk_buff *skb);
 
 #endif /* __A2MP_H */
diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c
index 894e53c..dc70ee6 100644
--- a/net/bluetooth/a2mp.c
+++ b/net/bluetooth/a2mp.c
@@ -552,3 +552,15 @@ static struct amp_mgr *amp_mgr_create(struct l2cap_conn *conn)
 
 	return mgr;
 }
+
+struct l2cap_chan *a2mp_channel_create(struct l2cap_conn *conn,
+				       struct sk_buff *skb)
+{
+	struct amp_mgr *mgr;
+
+	mgr = amp_mgr_create(conn);
+
+	BT_DBG("mgr: %p chan %p", mgr, mgr->a2mp_chan);
+
+	return mgr->a2mp_chan;
+}
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index bd9197c..9a89c47 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -37,6 +37,7 @@
 #include <net/bluetooth/hci_core.h>
 #include <net/bluetooth/l2cap.h>
 #include <net/bluetooth/smp.h>
+#include <net/bluetooth/a2mp.h>
 
 bool disable_ertm;
 
@@ -5167,10 +5168,15 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk
 
 	chan = l2cap_get_chan_by_scid(conn, cid);
 	if (!chan) {
-		BT_DBG("unknown cid 0x%4.4x", cid);
-		/* Drop packet and return */
-		kfree_skb(skb);
-		return 0;
+		if (cid == L2CAP_CID_A2MP) {
+			chan = a2mp_channel_create(conn, skb);
+			l2cap_chan_lock(chan);
+		} else {
+			BT_DBG("unknown cid 0x%4.4x", cid);
+			/* Drop packet and return */
+			kfree_skb(skb);
+			return 0;
+		}
 	}
 
 	BT_DBG("chan %p, len %d", chan, skb->len);
-- 
1.7.9.5


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

* Re: [PATCHv1 01/17] Bluetooth: A2MP: Create A2MP channel
  2012-05-23  7:49     ` Andrei Emeltchenko
@ 2012-05-23 15:44       ` Mat Martineau
  2012-05-24  7:51         ` Andrei Emeltchenko
  0 siblings, 1 reply; 104+ messages in thread
From: Mat Martineau @ 2012-05-23 15:44 UTC (permalink / raw)
  To: Andrei Emeltchenko; +Cc: linux-bluetooth, pkrystad


Hi Andrei -

On Wed, 23 May 2012, Andrei Emeltchenko wrote:

> Hi Mat,
>
> On Tue, May 22, 2012 at 10:45:07AM -0700, Mat Martineau wrote:
>>> +static struct l2cap_chan *a2mp_chan_open(struct l2cap_conn *conn)
>>> +{
>>> +	struct l2cap_chan *chan;
>>> +
>>> +	chan = l2cap_chan_create();
>>> +	if (!chan)
>>> +		return NULL;
>>> +
>>> +	BT_DBG("chan %p", chan);
>>> +
>>> +	hci_conn_hold(conn->hcon);
>>
>> Holding the hcon will keep the ACL open after all of the other L2CAP
>> channels have closed (unless I missed some code later in the patch
>> series).  The A2MP fixed channel should not keep the ACL open.  If
>> the connection is not held here, then there shouldn't be a put in
>> l2cap_chan_del for the A2MP channel either.
>
> l2cap_chan_del makes hci_conn_put, also for a2mp channel. The behavior is
> the same for fixed and normal channels.

And when does l2cap_chan_del get called for a fixed channel?  The 
fixed channel must not do an hci_conn_hold so the ACL is allowed to 
close when all dynamic L2CAP channels have closed.

--
Mat Martineau
Employee of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum


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

* Re: [PATCHv2 01/19] Bluetooth: Add unlink to L2CAP channel ops
  2012-05-23 15:37   ` [PATCHv2 01/19] Bluetooth: Add unlink to L2CAP channel ops Andrei Emeltchenko
@ 2012-05-23 23:13     ` Mat Martineau
  0 siblings, 0 replies; 104+ messages in thread
From: Mat Martineau @ 2012-05-23 23:13 UTC (permalink / raw)
  To: Andrei Emeltchenko; +Cc: linux-bluetooth


Andrei -

On Wed, 23 May 2012, Andrei Emeltchenko wrote:

> From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
>
> This helps to separate socket and socketless code. Now socket related
> operations moved to l2cap_sock in unlink callback for channels with sk.
>
> Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
> ---
> include/net/bluetooth/l2cap.h |    1 +
> net/bluetooth/l2cap_core.c    |   19 ++-----------------
> net/bluetooth/l2cap_sock.c    |   25 +++++++++++++++++++++++++
> 3 files changed, 28 insertions(+), 17 deletions(-)
>
> diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
> index 0142257..a017249 100644
> --- a/include/net/bluetooth/l2cap.h
> +++ b/include/net/bluetooth/l2cap.h
> @@ -529,6 +529,7 @@ struct l2cap_ops {
> 	void			(*state_change) (void *data, int state);
> 	struct sk_buff		*(*alloc_skb) (struct l2cap_chan *chan,
> 					       unsigned long len, int nb);
> +	void			(*unlink) (struct l2cap_chan *chan, int err);
> };
>
> struct l2cap_conn {
> diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
> index e31b005..c81b828 100644
> --- a/net/bluetooth/l2cap_core.c
> +++ b/net/bluetooth/l2cap_core.c
> @@ -493,9 +493,7 @@ static void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
>
> static void l2cap_chan_del(struct l2cap_chan *chan, int err)
> {
> -	struct sock *sk = chan->sk;
> 	struct l2cap_conn *conn = chan->conn;
> -	struct sock *parent = bt_sk(sk)->parent;
>
> 	__clear_chan_timer(chan);
>
> @@ -511,21 +509,8 @@ static void l2cap_chan_del(struct l2cap_chan *chan, int err)
> 		hci_conn_put(conn->hcon);
> 	}
>
> -	lock_sock(sk);
> -
> -	__l2cap_state_change(chan, BT_CLOSED);
> -	sock_set_flag(sk, SOCK_ZAPPED);
> -
> -	if (err)
> -		__l2cap_chan_set_err(chan, err);
> -
> -	if (parent) {
> -		bt_accept_unlink(sk);
> -		parent->sk_data_ready(parent, 0);
> -	} else
> -		sk->sk_state_change(sk);
> -
> -	release_sock(sk);
> +	if (chan->ops->unlink)
> +		chan->ops->unlink(chan, err);
>
> 	if (test_bit(CONF_NOT_COMPLETE, &chan->conf_state))
> 		return;
> diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c
> index 4d36605..6749d11 100644
> --- a/net/bluetooth/l2cap_sock.c
> +++ b/net/bluetooth/l2cap_sock.c
> @@ -954,6 +954,30 @@ static struct sk_buff *l2cap_sock_alloc_skb_cb(struct l2cap_chan *chan,
> 	return skb;
> }
>
> +static void l2cap_sock_unlink_cb(struct l2cap_chan *chan, int err)
> +{
> +	struct sock *sk = chan->sk;
> +	struct sock *parent = bt_sk(sk)->parent;
> +
> +	lock_sock(sk);
> +
> +	chan->state = BT_CLOSED;

I think this line had better stay in l2cap_chan_del - otherwise every 
unlink callback has to do it.  It's also the only modification to chan 
in here.  Since the channel must be locked before l2cap_chan_del is 
called anyway, I don't think it matters if chan->state is modified 
before or after the call to chan->ops->unlink.

> +	sk->sk_state = BT_CLOSED;
> +	sock_set_flag(sk, SOCK_ZAPPED);
> +
> +	if (err)
> +		sk->sk_err = err;
> +
> +	parent = bt_sk(sk)->parent;
> +	if (parent) {
> +		bt_accept_unlink(sk);
> +		parent->sk_data_ready(parent, 0);
> +	} else
> +		sk->sk_state_change(sk);
> +
> +	release_sock(sk);
> +}
> +
> static struct l2cap_ops l2cap_chan_ops = {
> 	.name		= "L2CAP Socket Interface",
> 	.new_connection	= l2cap_sock_new_connection_cb,
> @@ -961,6 +985,7 @@ static struct l2cap_ops l2cap_chan_ops = {
> 	.close		= l2cap_sock_close_cb,
> 	.state_change	= l2cap_sock_state_change_cb,
> 	.alloc_skb	= l2cap_sock_alloc_skb_cb,
> +	.unlink		= l2cap_sock_unlink_cb,
> };
>
> static void l2cap_sock_destruct(struct sock *sk)
> -- 
> 1.7.9.5



--
Mat Martineau
Employee of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum


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

* Re: [PATCHv2 02/19] Bluetooth: Add ready to L2CAP channel ops
  2012-05-23 15:37   ` [PATCHv2 02/19] Bluetooth: Add ready " Andrei Emeltchenko
@ 2012-05-23 23:16     ` Mat Martineau
  2012-05-24  7:59       ` Andrei Emeltchenko
  0 siblings, 1 reply; 104+ messages in thread
From: Mat Martineau @ 2012-05-23 23:16 UTC (permalink / raw)
  To: Andrei Emeltchenko; +Cc: linux-bluetooth


Andrei -

On Wed, 23 May 2012, Andrei Emeltchenko wrote:

> From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
>
> Addings ops->ready() helps to separate socket and socketless
> L2CAP channels.
>
> Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
> ---
> include/net/bluetooth/l2cap.h |    1 +
> net/bluetooth/l2cap_core.c    |   42 +++++++++++------------------------------
> net/bluetooth/l2cap_sock.c    |   28 +++++++++++++++++++++++++++
> 3 files changed, 40 insertions(+), 31 deletions(-)
>
> diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
> index a017249..83a67e8 100644
> --- a/include/net/bluetooth/l2cap.h
> +++ b/include/net/bluetooth/l2cap.h
> @@ -530,6 +530,7 @@ struct l2cap_ops {
> 	struct sk_buff		*(*alloc_skb) (struct l2cap_chan *chan,
> 					       unsigned long len, int nb);
> 	void			(*unlink) (struct l2cap_chan *chan, int err);
> +	void			(*ready) (struct l2cap_chan *chan);
> };
>
> struct l2cap_conn {
> diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
> index c81b828..d5ea8af 100644
> --- a/net/bluetooth/l2cap_core.c
> +++ b/net/bluetooth/l2cap_core.c
> @@ -407,7 +407,7 @@ struct l2cap_chan *l2cap_chan_create(void)
>
> 	atomic_set(&chan->refcnt, 1);
>
> -	/* This flag is cleared in l2cap_chan_ready() */
> +	/* This flag is cleared in l2cap chan ops->ready() */
> 	set_bit(CONF_NOT_COMPLETE, &chan->conf_state);
>
> 	BT_DBG("chan %p", chan);
> @@ -953,36 +953,13 @@ static void l2cap_send_conn_req(struct l2cap_chan *chan)
> 	l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_REQ, sizeof(req), &req);
> }
>
> -static void l2cap_chan_ready(struct l2cap_chan *chan)
> -{
> -	struct sock *sk = chan->sk;
> -	struct sock *parent;
> -
> -	lock_sock(sk);
> -
> -	parent = bt_sk(sk)->parent;
> -
> -	BT_DBG("sk %p, parent %p", sk, parent);
> -
> -	/* This clears all conf flags, including CONF_NOT_COMPLETE */
> -	chan->conf_state = 0;
> -	__clear_chan_timer(chan);
> -
> -	__l2cap_state_change(chan, BT_CONNECTED);
> -	sk->sk_state_change(sk);
> -
> -	if (parent)
> -		parent->sk_data_ready(parent, 0);
> -
> -	release_sock(sk);
> -}
> -
> static void l2cap_do_start(struct l2cap_chan *chan)
> {
> 	struct l2cap_conn *conn = chan->conn;
>
> 	if (conn->hcon->type == LE_LINK) {
> -		l2cap_chan_ready(chan);
> +		if (chan->ops->ready)
> +			chan->ops->ready(chan);
> 		return;
> 	}
>
> @@ -1242,8 +1219,8 @@ static void l2cap_conn_ready(struct l2cap_conn *conn)
>
> 		if (conn->hcon->type == LE_LINK) {
> 			if (smp_conn_security(conn, chan->sec_level))
> -				l2cap_chan_ready(chan);
> -
> +				if (chan->ops->ready)
> +					chan->ops->ready(chan);
> 		} else if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
> 			struct sock *sk = chan->sk;
> 			__clear_chan_timer(chan);
> @@ -3639,7 +3616,8 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr
> 		if (err < 0)
> 			l2cap_send_disconn_req(chan->conn, chan, -err);
> 		else
> -			l2cap_chan_ready(chan);
> +			if (chan->ops->ready)
> +				chan->ops->ready(chan);
>
> 		goto unlock;
> 	}
> @@ -3770,7 +3748,8 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr
> 		if (err < 0)
> 			l2cap_send_disconn_req(chan->conn, chan, -err);
> 		else
> -			l2cap_chan_ready(chan);
> +			if (chan->ops->ready)
> +				chan->ops->ready(chan);
> 	}
>
> done:
> @@ -5420,7 +5399,8 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
> 		if (chan->scid == L2CAP_CID_LE_DATA) {
> 			if (!status && encrypt) {
> 				chan->sec_level = hcon->sec_level;
> -				l2cap_chan_ready(chan);
> +				if (chan->ops->ready)
> +					chan->ops->ready(chan);
> 			}
>
> 			l2cap_chan_unlock(chan);
> diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c
> index 6749d11..2e078c4 100644
> --- a/net/bluetooth/l2cap_sock.c
> +++ b/net/bluetooth/l2cap_sock.c
> @@ -978,6 +978,33 @@ static void l2cap_sock_unlink_cb(struct l2cap_chan *chan, int err)
> 	release_sock(sk);
> }
>
> +static void l2cap_sock_chan_ready_cb(struct l2cap_chan *chan)
> +{
> +	struct sock *sk = chan->sk;
> +	struct sock *parent;
> +
> +	lock_sock(sk);
> +
> +	parent = bt_sk(sk)->parent;
> +
> +	BT_DBG("sk %p, parent %p", sk, parent);
> +
> +	__clear_chan_timer(chan);
> +
> +	/* This clears all conf flags, including CONF_NOT_COMPLETE */
> +	chan->conf_state = 0;
> +
> +	chan->state = BT_CONNECTED;

Similar to patch 1, would there be some benefit to leaving the chan 
code (timer clearing, state and conf_state modification) in 
l2cap_core?  These things need to happen even if chan->ops->ready is 
NULL.

> +	sk->sk_state = BT_CONNECTED;
> +
> +	sk->sk_state_change(sk);
> +
> +	if (parent)
> +		parent->sk_data_ready(parent, 0);
> +
> +	release_sock(sk);
> +}
> +
> static struct l2cap_ops l2cap_chan_ops = {
> 	.name		= "L2CAP Socket Interface",
> 	.new_connection	= l2cap_sock_new_connection_cb,
> @@ -986,6 +1013,7 @@ static struct l2cap_ops l2cap_chan_ops = {
> 	.state_change	= l2cap_sock_state_change_cb,
> 	.alloc_skb	= l2cap_sock_alloc_skb_cb,
> 	.unlink		= l2cap_sock_unlink_cb,
> +	.ready		= l2cap_sock_chan_ready_cb,
> };
>
> static void l2cap_sock_destruct(struct sock *sk)
> -- 
> 1.7.9.5

--
Mat Martineau
Employee of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum

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

* Re: [PATCHv2 19/19] Bluetooth: A2MP: Manage incoming connections
  2012-05-23 15:37   ` [PATCHv2 19/19] Bluetooth: A2MP: Manage incoming connections Andrei Emeltchenko
@ 2012-05-23 23:30     ` Mat Martineau
  2012-05-24 11:43       ` Andrei Emeltchenko
  0 siblings, 1 reply; 104+ messages in thread
From: Mat Martineau @ 2012-05-23 23:30 UTC (permalink / raw)
  To: Andrei Emeltchenko; +Cc: linux-bluetooth


Andrei -

On Wed, 23 May 2012, Andrei Emeltchenko wrote:

> From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
>
> Handle incoming A2MP connection by creating AMP manager and
> processing A2MP messages.
>
> Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
> ---
> include/net/bluetooth/a2mp.h |    4 ++++
> net/bluetooth/a2mp.c         |   12 ++++++++++++
> net/bluetooth/l2cap_core.c   |   14 ++++++++++----
> 3 files changed, 26 insertions(+), 4 deletions(-)
>
> diff --git a/include/net/bluetooth/a2mp.h b/include/net/bluetooth/a2mp.h
> index 96f9cc2..6a76e0a 100644
> --- a/include/net/bluetooth/a2mp.h
> +++ b/include/net/bluetooth/a2mp.h
> @@ -15,6 +15,8 @@
> #ifndef __A2MP_H
> #define __A2MP_H
>
> +#include <net/bluetooth/l2cap.h>
> +
> #define A2MP_FEAT_EXT	0x8000
>
> struct amp_mgr {
> @@ -118,5 +120,7 @@ struct a2mp_physlink_rsp {
>
> void amp_mgr_get(struct amp_mgr *mgr);
> int amp_mgr_put(struct amp_mgr *mgr);
> +struct l2cap_chan *a2mp_channel_create(struct l2cap_conn *conn,
> +				       struct sk_buff *skb);
>
> #endif /* __A2MP_H */
> diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c
> index 894e53c..dc70ee6 100644
> --- a/net/bluetooth/a2mp.c
> +++ b/net/bluetooth/a2mp.c
> @@ -552,3 +552,15 @@ static struct amp_mgr *amp_mgr_create(struct l2cap_conn *conn)
>
> 	return mgr;
> }
> +
> +struct l2cap_chan *a2mp_channel_create(struct l2cap_conn *conn,
> +				       struct sk_buff *skb)
> +{
> +	struct amp_mgr *mgr;
> +
> +	mgr = amp_mgr_create(conn);
> +
> +	BT_DBG("mgr: %p chan %p", mgr, mgr->a2mp_chan);
> +
> +	return mgr->a2mp_chan;

mgr can be NULL.

> +}
> diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
> index bd9197c..9a89c47 100644
> --- a/net/bluetooth/l2cap_core.c
> +++ b/net/bluetooth/l2cap_core.c
> @@ -37,6 +37,7 @@
> #include <net/bluetooth/hci_core.h>
> #include <net/bluetooth/l2cap.h>
> #include <net/bluetooth/smp.h>
> +#include <net/bluetooth/a2mp.h>
>
> bool disable_ertm;
>
> @@ -5167,10 +5168,15 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk
>
> 	chan = l2cap_get_chan_by_scid(conn, cid);
> 	if (!chan) {
> -		BT_DBG("unknown cid 0x%4.4x", cid);
> -		/* Drop packet and return */
> -		kfree_skb(skb);
> -		return 0;
> +		if (cid == L2CAP_CID_A2MP) {
> +			chan = a2mp_channel_create(conn, skb);

If amp_mgr_create returned NULL, then you would have to handle NULL 
from a2mp_channel_create too.

> +			l2cap_chan_lock(chan);
> +		} else {
> +			BT_DBG("unknown cid 0x%4.4x", cid);
> +			/* Drop packet and return */
> +			kfree_skb(skb);
> +			return 0;
> +		}
> 	}
>
> 	BT_DBG("chan %p, len %d", chan, skb->len);
> -- 
> 1.7.9.5

--
Mat Martineau
Employee of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum



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

* Re: [PATCHv1 01/17] Bluetooth: A2MP: Create A2MP channel
  2012-05-23 15:44       ` Mat Martineau
@ 2012-05-24  7:51         ` Andrei Emeltchenko
  2012-05-24 15:59           ` Mat Martineau
  0 siblings, 1 reply; 104+ messages in thread
From: Andrei Emeltchenko @ 2012-05-24  7:51 UTC (permalink / raw)
  To: Mat Martineau; +Cc: linux-bluetooth, pkrystad

Hi Mat,

On Wed, May 23, 2012 at 08:44:22AM -0700, Mat Martineau wrote:
> >>>+static struct l2cap_chan *a2mp_chan_open(struct l2cap_conn *conn)
> >>>+{
> >>>+	struct l2cap_chan *chan;
> >>>+
> >>>+	chan = l2cap_chan_create();
> >>>+	if (!chan)
> >>>+		return NULL;
> >>>+
> >>>+	BT_DBG("chan %p", chan);
> >>>+
> >>>+	hci_conn_hold(conn->hcon);
> >>
> >>Holding the hcon will keep the ACL open after all of the other L2CAP
> >>channels have closed (unless I missed some code later in the patch
> >>series).  The A2MP fixed channel should not keep the ACL open.  If
> >>the connection is not held here, then there shouldn't be a put in
> >>l2cap_chan_del for the A2MP channel either.
> >
> >l2cap_chan_del makes hci_conn_put, also for a2mp channel. The behavior is
> >the same for fixed and normal channels.
> 
> And when does l2cap_chan_del get called for a fixed channel?  The
> fixed channel must not do an hci_conn_hold so the ACL is allowed to
> close when all dynamic L2CAP channels have closed.

The current approach is to have amp_mgr for hci_conn. It will be freed
when in hci_conn_del together with other l2cap channels in
hci_chan_list_flush and then we make amp_mgr_put() and destroy mgr.

The idea is to make a2mp chan similar to other chans and other chans do
hci_conn_hold and hci_conn_put. Otherwise I would need to add extra checks
before hci_conn_put which is ugly.

I've tested this with PTS and no memory leaks found so far.

Best regards 
Andrei Emeltchenko 


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

* Re: [PATCHv2 02/19] Bluetooth: Add ready to L2CAP channel ops
  2012-05-23 23:16     ` Mat Martineau
@ 2012-05-24  7:59       ` Andrei Emeltchenko
  0 siblings, 0 replies; 104+ messages in thread
From: Andrei Emeltchenko @ 2012-05-24  7:59 UTC (permalink / raw)
  To: Mat Martineau; +Cc: linux-bluetooth

Hi Mat,

On Wed, May 23, 2012 at 04:16:37PM -0700, Mat Martineau wrote:
> >+static void l2cap_sock_chan_ready_cb(struct l2cap_chan *chan)
> >+{
> >+	struct sock *sk = chan->sk;
> >+	struct sock *parent;
> >+
> >+	lock_sock(sk);
> >+
> >+	parent = bt_sk(sk)->parent;
> >+
> >+	BT_DBG("sk %p, parent %p", sk, parent);
> >+
> >+	__clear_chan_timer(chan);
> >+
> >+	/* This clears all conf flags, including CONF_NOT_COMPLETE */
> >+	chan->conf_state = 0;
> >+
> >+	chan->state = BT_CONNECTED;
> 
> Similar to patch 1, would there be some benefit to leaving the chan
> code (timer clearing, state and conf_state modification) in
> l2cap_core?  These things need to happen even if chan->ops->ready is
> NULL.

This can be done, then I would need to create new function like
l2cap_chan_ready which do chan code and calls ready callback. I will try
to come out with some solution later today.

Best regards 
Andrei Emeltchenko 


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

* [PATCHv3 00/18] Bluetooth A2MP implementation
  2012-05-18 14:25 [PATCHv1 00/17] Bluetooth A2MP implementation Andrei Emeltchenko
                   ` (18 preceding siblings ...)
  2012-05-23 15:37 ` [PATCHv2 00/19] " Andrei Emeltchenko
@ 2012-05-24 11:38 ` Andrei Emeltchenko
  2012-05-24 11:38   ` [PATCHv3 01/18] Bluetooth: Add ready to L2CAP channel ops Andrei Emeltchenko
                     ` (17 more replies)
  2012-05-29 10:59 ` [PATCHv4 00/17] Bluetooth A2MP implementation Andrei Emeltchenko
  20 siblings, 18 replies; 104+ messages in thread
From: Andrei Emeltchenko @ 2012-05-24 11:38 UTC (permalink / raw)
  To: linux-bluetooth

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

Basic A2MP implementation.

Changes:
	* PATCHv3: Skipped unlink callback since Gustavo seems to have better
	approach, added NULL pointer checks reported by Mat.
	* PATCHv2: Rebased against recent changes, changed amp_mgr list to pointer
	in hci_conn, reworked handling fixed channels and create A2MP channel patches,
	adding unlink and ready callbacks to get rid of socket dependecies in L2CAP and
	other minor fixes.
	* PATCHv1: Rebasing against latest tree and minor fixes.
	* RFCv7: Taking comments from review in linux-bluetooth.
	* RFCv6: Remove some unneded check for sk since they are in different path
	(A2MP decoded as a data channel wrt L2CAP signalling channel). Style fixes.
	* RFCv5: Fix memory leaks, sparse warnings and taking comments from upstream.
	* RFCv4: redesign code to use l2cap channel lock instead of socket lock
	and general modifications. Basic implementation of HCI callback interface.
	* RFCv3: redesign code to use l2cap functions instead of kernel sockets
	L2CAP functions modified to work with channels without sk.
	* RFCv2: rebased against "workqueue" patches.
	* RFCv1: added refcnt to amp_mgr, fixed sleeping in atomic

Initially code was based of reference implementations below:

References: Code Aurora (git://codeaurora.org/kernel/msm.git) and Atheros
(search for: [PATCH 2/3] Add a2mp protocol/AMP manager, by Atheros Linux BT3)
implementations.

Andrei Emeltchenko (18):
  Bluetooth: Add ready to L2CAP channel ops
  Bluetooth: A2MP: Create A2MP channel
  Bluetooth: A2MP: AMP Manager basic functions
  Bluetooth: A2MP: Build and Send msg helpers
  Bluetooth: A2MP: Add chan callbacks
  Bluetooth: A2MP: Definitions for A2MP commands
  Bluetooth: A2MP: Define A2MP status codes
  Bluetooth: A2MP: Process A2MP messages
  Bluetooth: A2MP: Process A2MP Command Reject
  Bluetooth: A2MP: Process A2MP Discover Request
  Bluetooth: A2MP: Process A2MP Change Notify
  Bluetooth: A2MP: Process A2MP Get Info Request
  Bluetooth: A2MP: Process A2MP Get AMP Assoc Request
  Bluetooth: A2MP: Process A2MP Create Physlink Request
  Bluetooth: A2MP: Process A2MP Disc Physlink Request
  Bluetooth: A2MP: Process A2MP Command Responses
  Bluetooth: A2MP: Handling fixed channels
  Bluetooth: A2MP: Manage incoming connections

 include/net/bluetooth/a2mp.h     |  126 +++++++++
 include/net/bluetooth/hci.h      |    3 +
 include/net/bluetooth/hci_core.h |   14 +
 include/net/bluetooth/l2cap.h    |    8 +
 net/bluetooth/Makefile           |    3 +-
 net/bluetooth/a2mp.c             |  570 ++++++++++++++++++++++++++++++++++++++
 net/bluetooth/hci_conn.c         |    4 +
 net/bluetooth/l2cap_core.c       |   65 +++--
 net/bluetooth/l2cap_sock.c       |   22 ++
 9 files changed, 789 insertions(+), 26 deletions(-)
 create mode 100644 include/net/bluetooth/a2mp.h
 create mode 100644 net/bluetooth/a2mp.c

-- 
1.7.9.5


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

* [PATCHv3 01/18] Bluetooth: Add ready to L2CAP channel ops
  2012-05-24 11:38 ` [PATCHv3 00/18] Bluetooth A2MP implementation Andrei Emeltchenko
@ 2012-05-24 11:38   ` Andrei Emeltchenko
  2012-05-24 11:38   ` [PATCHv3 02/18] Bluetooth: A2MP: Create A2MP channel Andrei Emeltchenko
                     ` (16 subsequent siblings)
  17 siblings, 0 replies; 104+ messages in thread
From: Andrei Emeltchenko @ 2012-05-24 11:38 UTC (permalink / raw)
  To: linux-bluetooth

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

Addings ops->ready() helps to separate socket and socketless
L2CAP channels.

Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
 include/net/bluetooth/l2cap.h |    1 +
 net/bluetooth/l2cap_core.c    |   23 +++++------------------
 net/bluetooth/l2cap_sock.c    |   22 ++++++++++++++++++++++
 3 files changed, 28 insertions(+), 18 deletions(-)

diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index a017249..83a67e8 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -530,6 +530,7 @@ struct l2cap_ops {
 	struct sk_buff		*(*alloc_skb) (struct l2cap_chan *chan,
 					       unsigned long len, int nb);
 	void			(*unlink) (struct l2cap_chan *chan, int err);
+	void			(*ready) (struct l2cap_chan *chan);
 };
 
 struct l2cap_conn {
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 8ca6e8f..16ec122 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -407,7 +407,7 @@ struct l2cap_chan *l2cap_chan_create(void)
 
 	atomic_set(&chan->refcnt, 1);
 
-	/* This flag is cleared in l2cap_chan_ready() */
+	/* This flag is cleared in l2cap chan ops->ready() */
 	set_bit(CONF_NOT_COMPLETE, &chan->conf_state);
 
 	BT_DBG("chan %p", chan);
@@ -955,26 +955,14 @@ static void l2cap_send_conn_req(struct l2cap_chan *chan)
 
 static void l2cap_chan_ready(struct l2cap_chan *chan)
 {
-	struct sock *sk = chan->sk;
-	struct sock *parent;
-
-	lock_sock(sk);
-
-	parent = bt_sk(sk)->parent;
-
-	BT_DBG("sk %p, parent %p", sk, parent);
+	__clear_chan_timer(chan);
 
 	/* This clears all conf flags, including CONF_NOT_COMPLETE */
 	chan->conf_state = 0;
-	__clear_chan_timer(chan);
-
-	__l2cap_state_change(chan, BT_CONNECTED);
-	sk->sk_state_change(sk);
+	chan->state = BT_CONNECTED;
 
-	if (parent)
-		parent->sk_data_ready(parent, 0);
-
-	release_sock(sk);
+	if (chan->ops->ready)
+		chan->ops->ready(chan);
 }
 
 static void l2cap_do_start(struct l2cap_chan *chan)
@@ -1243,7 +1231,6 @@ static void l2cap_conn_ready(struct l2cap_conn *conn)
 		if (conn->hcon->type == LE_LINK) {
 			if (smp_conn_security(conn, chan->sec_level))
 				l2cap_chan_ready(chan);
-
 		} else if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
 			struct sock *sk = chan->sk;
 			__clear_chan_timer(chan);
diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c
index 6749d11..3d97b58 100644
--- a/net/bluetooth/l2cap_sock.c
+++ b/net/bluetooth/l2cap_sock.c
@@ -978,6 +978,27 @@ static void l2cap_sock_unlink_cb(struct l2cap_chan *chan, int err)
 	release_sock(sk);
 }
 
+static void l2cap_sock_chan_ready_cb(struct l2cap_chan *chan)
+{
+	struct sock *sk = chan->sk;
+	struct sock *parent;
+
+	lock_sock(sk);
+
+	parent = bt_sk(sk)->parent;
+
+	BT_DBG("sk %p, parent %p", sk, parent);
+
+	sk->sk_state = BT_CONNECTED;
+
+	sk->sk_state_change(sk);
+
+	if (parent)
+		parent->sk_data_ready(parent, 0);
+
+	release_sock(sk);
+}
+
 static struct l2cap_ops l2cap_chan_ops = {
 	.name		= "L2CAP Socket Interface",
 	.new_connection	= l2cap_sock_new_connection_cb,
@@ -986,6 +1007,7 @@ static struct l2cap_ops l2cap_chan_ops = {
 	.state_change	= l2cap_sock_state_change_cb,
 	.alloc_skb	= l2cap_sock_alloc_skb_cb,
 	.unlink		= l2cap_sock_unlink_cb,
+	.ready		= l2cap_sock_chan_ready_cb,
 };
 
 static void l2cap_sock_destruct(struct sock *sk)
-- 
1.7.9.5


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

* [PATCHv3 02/18] Bluetooth: A2MP: Create A2MP channel
  2012-05-24 11:38 ` [PATCHv3 00/18] Bluetooth A2MP implementation Andrei Emeltchenko
  2012-05-24 11:38   ` [PATCHv3 01/18] Bluetooth: Add ready to L2CAP channel ops Andrei Emeltchenko
@ 2012-05-24 11:38   ` Andrei Emeltchenko
  2012-05-24 11:38   ` [PATCHv3 03/18] Bluetooth: A2MP: AMP Manager basic functions Andrei Emeltchenko
                     ` (15 subsequent siblings)
  17 siblings, 0 replies; 104+ messages in thread
From: Andrei Emeltchenko @ 2012-05-24 11:38 UTC (permalink / raw)
  To: linux-bluetooth

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

Create and initialize fixed A2MP channel

Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
 include/net/bluetooth/l2cap.h |    6 ++++
 net/bluetooth/Makefile        |    3 +-
 net/bluetooth/a2mp.c          |   67 +++++++++++++++++++++++++++++++++++++++++
 net/bluetooth/l2cap_core.c    |    6 ++--
 4 files changed, 78 insertions(+), 4 deletions(-)
 create mode 100644 net/bluetooth/a2mp.c

diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index 83a67e8..b022329 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -52,6 +52,8 @@
 #define L2CAP_CONN_TIMEOUT		msecs_to_jiffies(40000)
 #define L2CAP_INFO_TIMEOUT		msecs_to_jiffies(4000)
 
+#define L2CAP_A2MP_DEFAULT_MTU		670
+
 /* L2CAP socket address */
 struct sockaddr_l2 {
 	sa_family_t	l2_family;
@@ -232,6 +234,7 @@ struct l2cap_conn_rsp {
 /* channel indentifier */
 #define L2CAP_CID_SIGNALING	0x0001
 #define L2CAP_CID_CONN_LESS	0x0002
+#define L2CAP_CID_A2MP		0x0003
 #define L2CAP_CID_LE_DATA	0x0004
 #define L2CAP_CID_LE_SIGNALING	0x0005
 #define L2CAP_CID_SMP		0x0006
@@ -752,5 +755,8 @@ int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len,
 void l2cap_chan_busy(struct l2cap_chan *chan, int busy);
 int l2cap_chan_check_security(struct l2cap_chan *chan);
 void l2cap_chan_set_defaults(struct l2cap_chan *chan);
+int l2cap_ertm_init(struct l2cap_chan *chan);
+void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan);
+void l2cap_chan_del(struct l2cap_chan *chan, int err);
 
 #endif /* __L2CAP_H */
diff --git a/net/bluetooth/Makefile b/net/bluetooth/Makefile
index 2dc5a57..fa6d94a 100644
--- a/net/bluetooth/Makefile
+++ b/net/bluetooth/Makefile
@@ -9,4 +9,5 @@ obj-$(CONFIG_BT_CMTP)	+= cmtp/
 obj-$(CONFIG_BT_HIDP)	+= hidp/
 
 bluetooth-y := af_bluetooth.o hci_core.o hci_conn.o hci_event.o mgmt.o \
-	hci_sock.o hci_sysfs.o l2cap_core.o l2cap_sock.o smp.o sco.o lib.o
+	hci_sock.o hci_sysfs.o l2cap_core.o l2cap_sock.o smp.o sco.o lib.o \
+	a2mp.o
diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c
new file mode 100644
index 0000000..d1574f5
--- /dev/null
+++ b/net/bluetooth/a2mp.c
@@ -0,0 +1,67 @@
+/*
+   Copyright (c) 2010,2011 Code Aurora Forum.  All rights reserved.
+   Copyright (c) 2011,2012 Intel Corp.
+
+   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.
+*/
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+#include <net/bluetooth/l2cap.h>
+
+static struct l2cap_ops a2mp_chan_ops = {
+	.name = "L2CAP A2MP channel",
+};
+
+static struct l2cap_chan *a2mp_chan_open(struct l2cap_conn *conn)
+{
+	struct l2cap_chan *chan;
+	int err;
+
+	chan = l2cap_chan_create();
+	if (!chan)
+		return NULL;
+
+	BT_DBG("chan %p", chan);
+
+	hci_conn_hold(conn->hcon);
+
+	chan->omtu = L2CAP_A2MP_DEFAULT_MTU;
+	chan->imtu = L2CAP_A2MP_DEFAULT_MTU;
+	chan->flush_to = L2CAP_DEFAULT_FLUSH_TO;
+
+	chan->ops = &a2mp_chan_ops;
+
+	l2cap_chan_set_defaults(chan);
+	chan->remote_max_tx = chan->max_tx;
+	chan->remote_tx_win = chan->tx_win;
+
+	chan->retrans_timeout = L2CAP_DEFAULT_RETRANS_TO;
+	chan->monitor_timeout = L2CAP_DEFAULT_MONITOR_TO;
+
+	skb_queue_head_init(&chan->tx_q);
+
+	chan->mode = L2CAP_MODE_ERTM;
+
+	err = l2cap_ertm_init(chan);
+	if (err < 0) {
+		l2cap_chan_del(chan, 0);
+		return NULL;
+	}
+
+	chan->conf_state = 0;
+
+	l2cap_chan_add(conn, chan);
+
+	chan->remote_mps = chan->omtu;
+	chan->mps = chan->omtu;
+
+	return chan;
+}
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 16ec122..275b8f7 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -484,14 +484,14 @@ static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
 	list_add(&chan->list, &conn->chan_l);
 }
 
-static void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
+void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
 {
 	mutex_lock(&conn->chan_lock);
 	__l2cap_chan_add(conn, chan);
 	mutex_unlock(&conn->chan_lock);
 }
 
-static void l2cap_chan_del(struct l2cap_chan *chan, int err)
+void l2cap_chan_del(struct l2cap_chan *chan, int err)
 {
 	struct l2cap_conn *conn = chan->conn;
 
@@ -2722,7 +2722,7 @@ static void l2cap_ack_timeout(struct work_struct *work)
 	l2cap_chan_put(chan);
 }
 
-static inline int l2cap_ertm_init(struct l2cap_chan *chan)
+int l2cap_ertm_init(struct l2cap_chan *chan)
 {
 	int err;
 
-- 
1.7.9.5


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

* [PATCHv3 03/18] Bluetooth: A2MP: AMP Manager basic functions
  2012-05-24 11:38 ` [PATCHv3 00/18] Bluetooth A2MP implementation Andrei Emeltchenko
  2012-05-24 11:38   ` [PATCHv3 01/18] Bluetooth: Add ready to L2CAP channel ops Andrei Emeltchenko
  2012-05-24 11:38   ` [PATCHv3 02/18] Bluetooth: A2MP: Create A2MP channel Andrei Emeltchenko
@ 2012-05-24 11:38   ` Andrei Emeltchenko
  2012-05-24 11:38   ` [PATCHv3 04/18] Bluetooth: A2MP: Build and Send msg helpers Andrei Emeltchenko
                     ` (14 subsequent siblings)
  17 siblings, 0 replies; 104+ messages in thread
From: Andrei Emeltchenko @ 2012-05-24 11:38 UTC (permalink / raw)
  To: linux-bluetooth

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

Define AMP Manager and some basic functions.

Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
 include/net/bluetooth/a2mp.h     |   30 +++++++++++++++++++++
 include/net/bluetooth/hci_core.h |    1 +
 net/bluetooth/a2mp.c             |   54 ++++++++++++++++++++++++++++++++++++++
 net/bluetooth/hci_conn.c         |    4 +++
 4 files changed, 89 insertions(+)
 create mode 100644 include/net/bluetooth/a2mp.h

diff --git a/include/net/bluetooth/a2mp.h b/include/net/bluetooth/a2mp.h
new file mode 100644
index 0000000..ff47540
--- /dev/null
+++ b/include/net/bluetooth/a2mp.h
@@ -0,0 +1,30 @@
+/*
+   Copyright (c) 2010,2011 Code Aurora Forum.  All rights reserved.
+   Copyright (c) 2011,2012 Intel Corp.
+
+   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 __A2MP_H
+#define __A2MP_H
+
+struct amp_mgr {
+	struct l2cap_conn	*l2cap_conn;
+	struct l2cap_chan	*a2mp_chan;
+	struct kref		kref;
+	__u8			ident;
+	__u8			handle;
+	unsigned long		flags;
+};
+
+void amp_mgr_get(struct amp_mgr *mgr);
+int amp_mgr_put(struct amp_mgr *mgr);
+
+#endif /* __A2MP_H */
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index d584a47..6e64b76 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -332,6 +332,7 @@ struct hci_conn {
 	void		*l2cap_data;
 	void		*sco_data;
 	void		*smp_conn;
+	struct amp_mgr	*amp_mgr;
 
 	struct hci_conn	*link;
 
diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c
index d1574f5..ea900fb 100644
--- a/net/bluetooth/a2mp.c
+++ b/net/bluetooth/a2mp.c
@@ -15,6 +15,7 @@
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
 #include <net/bluetooth/l2cap.h>
+#include <net/bluetooth/a2mp.h>
 
 static struct l2cap_ops a2mp_chan_ops = {
 	.name = "L2CAP A2MP channel",
@@ -65,3 +66,56 @@ static struct l2cap_chan *a2mp_chan_open(struct l2cap_conn *conn)
 
 	return chan;
 }
+
+/* AMP Manager functions */
+void amp_mgr_get(struct amp_mgr *mgr)
+{
+	BT_DBG("mgr %p", mgr);
+
+	kref_get(&mgr->kref);
+}
+
+static void amp_mgr_destroy(struct kref *kref)
+{
+	struct amp_mgr *mgr = container_of(kref, struct amp_mgr, kref);
+
+	BT_DBG("mgr %p", mgr);
+
+	kfree(mgr);
+}
+
+int amp_mgr_put(struct amp_mgr *mgr)
+{
+	BT_DBG("mgr %p", mgr);
+
+	return kref_put(&mgr->kref, &amp_mgr_destroy);
+}
+
+static struct amp_mgr *amp_mgr_create(struct l2cap_conn *conn)
+{
+	struct amp_mgr *mgr;
+	struct l2cap_chan *chan;
+
+	mgr = kzalloc(sizeof(*mgr), GFP_KERNEL);
+	if (!mgr)
+		return NULL;
+
+	BT_DBG("conn %p mgr %p", conn, mgr);
+
+	mgr->l2cap_conn = conn;
+
+	chan = a2mp_chan_open(conn);
+	if (!chan) {
+		kfree(mgr);
+		return NULL;
+	}
+
+	mgr->a2mp_chan = chan;
+	chan->data = mgr;
+
+	conn->hcon->amp_mgr = mgr;
+
+	kref_init(&mgr->kref);
+
+	return mgr;
+}
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index 8163ee1..111e549 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -28,6 +28,7 @@
 
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
+#include <net/bluetooth/a2mp.h>
 
 static void hci_le_connect(struct hci_conn *conn)
 {
@@ -411,6 +412,9 @@ int hci_conn_del(struct hci_conn *conn)
 
 	hci_chan_list_flush(conn);
 
+	if (conn->amp_mgr)
+		amp_mgr_put(conn->amp_mgr);
+
 	hci_conn_hash_del(hdev, conn);
 	if (hdev->notify)
 		hdev->notify(hdev, HCI_NOTIFY_CONN_DEL);
-- 
1.7.9.5


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

* [PATCHv3 04/18] Bluetooth: A2MP: Build and Send msg helpers
  2012-05-24 11:38 ` [PATCHv3 00/18] Bluetooth A2MP implementation Andrei Emeltchenko
                     ` (2 preceding siblings ...)
  2012-05-24 11:38   ` [PATCHv3 03/18] Bluetooth: A2MP: AMP Manager basic functions Andrei Emeltchenko
@ 2012-05-24 11:38   ` Andrei Emeltchenko
  2012-05-24 11:38   ` [PATCHv3 05/18] Bluetooth: A2MP: Add chan callbacks Andrei Emeltchenko
                     ` (13 subsequent siblings)
  17 siblings, 0 replies; 104+ messages in thread
From: Andrei Emeltchenko @ 2012-05-24 11:38 UTC (permalink / raw)
  To: linux-bluetooth

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

Helper function to build and send A2MP messages.

Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
 include/net/bluetooth/a2mp.h |    7 +++++++
 net/bluetooth/a2mp.c         |   46 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 53 insertions(+)

diff --git a/include/net/bluetooth/a2mp.h b/include/net/bluetooth/a2mp.h
index ff47540..654df60 100644
--- a/include/net/bluetooth/a2mp.h
+++ b/include/net/bluetooth/a2mp.h
@@ -24,6 +24,13 @@ struct amp_mgr {
 	unsigned long		flags;
 };
 
+struct a2mp_cmd {
+	__u8	code;
+	__u8	ident;
+	__le16	len;
+	__u8	data[0];
+} __packed;
+
 void amp_mgr_get(struct amp_mgr *mgr);
 int amp_mgr_put(struct amp_mgr *mgr);
 
diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c
index ea900fb..e7e5f5f 100644
--- a/net/bluetooth/a2mp.c
+++ b/net/bluetooth/a2mp.c
@@ -17,6 +17,52 @@
 #include <net/bluetooth/l2cap.h>
 #include <net/bluetooth/a2mp.h>
 
+/* A2MP build & send command helper functions */
+static struct a2mp_cmd *__a2mp_build(u8 code, u8 ident, u16 len, void *data)
+{
+	struct a2mp_cmd *cmd;
+	int plen;
+
+	plen = sizeof(*cmd) + len;
+	cmd = kzalloc(plen, GFP_KERNEL);
+	if (!cmd)
+		return NULL;
+
+	cmd->code = code;
+	cmd->ident = ident;
+	cmd->len = cpu_to_le16(len);
+
+	memcpy(cmd->data, data, len);
+
+	return cmd;
+}
+
+static void a2mp_send(struct amp_mgr *mgr, u8 code, u8 ident, u16 len,
+		      void *data)
+{
+	struct l2cap_chan *chan = mgr->a2mp_chan;
+	struct a2mp_cmd *cmd;
+	u16 total_len = len + sizeof(*cmd);
+	struct kvec iv;
+	struct msghdr msg;
+
+	cmd = __a2mp_build(code, ident, len, data);
+	if (!cmd)
+		return;
+
+	iv.iov_base = cmd;
+	iv.iov_len = total_len;
+
+	memset(&msg, 0, sizeof(msg));
+
+	msg.msg_iov = (struct iovec *) &iv;
+	msg.msg_iovlen = 1;
+
+	l2cap_chan_send(chan, &msg, total_len, 0);
+
+	kfree(cmd);
+}
+
 static struct l2cap_ops a2mp_chan_ops = {
 	.name = "L2CAP A2MP channel",
 };
-- 
1.7.9.5


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

* [PATCHv3 05/18] Bluetooth: A2MP: Add chan callbacks
  2012-05-24 11:38 ` [PATCHv3 00/18] Bluetooth A2MP implementation Andrei Emeltchenko
                     ` (3 preceding siblings ...)
  2012-05-24 11:38   ` [PATCHv3 04/18] Bluetooth: A2MP: Build and Send msg helpers Andrei Emeltchenko
@ 2012-05-24 11:38   ` Andrei Emeltchenko
  2012-05-25 12:20     ` Gustavo Padovan
  2012-05-24 11:38   ` [PATCHv3 06/18] Bluetooth: A2MP: Definitions for A2MP commands Andrei Emeltchenko
                     ` (12 subsequent siblings)
  17 siblings, 1 reply; 104+ messages in thread
From: Andrei Emeltchenko @ 2012-05-24 11:38 UTC (permalink / raw)
  To: linux-bluetooth

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

Add state change, close and skb allocation callbacks.

Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
 net/bluetooth/a2mp.c |   40 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 40 insertions(+)

diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c
index e7e5f5f..eb98541 100644
--- a/net/bluetooth/a2mp.c
+++ b/net/bluetooth/a2mp.c
@@ -63,8 +63,46 @@ static void a2mp_send(struct amp_mgr *mgr, u8 code, u8 ident, u16 len,
 	kfree(cmd);
 }
 
+static void a2mp_chan_state_change_cb(void *data, int state)
+{
+	struct amp_mgr *mgr = data;
+	struct l2cap_chan *chan;
+
+	if (!mgr)
+		return;
+
+	chan = mgr->a2mp_chan;
+
+	BT_DBG("chan %p state %s", chan, state_to_string(state));
+
+	chan->state = state;
+
+	switch (state) {
+	case BT_CLOSED:
+		if (mgr)
+			amp_mgr_put(mgr);
+		break;
+	}
+}
+
+static void a2mp_chan_close_cb(void *data)
+{
+	struct amp_mgr *mgr = data;
+
+	l2cap_chan_destroy(mgr->a2mp_chan);
+}
+
+static struct sk_buff *a2mp_chan_alloc_skb_cb(struct l2cap_chan *chan,
+					      unsigned long len, int nb)
+{
+	return bt_skb_alloc(len, GFP_KERNEL);
+}
+
 static struct l2cap_ops a2mp_chan_ops = {
 	.name = "L2CAP A2MP channel",
+	.state_change = a2mp_chan_state_change_cb,
+	.close = a2mp_chan_close_cb,
+	.alloc_skb = a2mp_chan_alloc_skb_cb,
 };
 
 static struct l2cap_chan *a2mp_chan_open(struct l2cap_conn *conn)
@@ -110,6 +148,8 @@ static struct l2cap_chan *a2mp_chan_open(struct l2cap_conn *conn)
 	chan->remote_mps = chan->omtu;
 	chan->mps = chan->omtu;
 
+	chan->state = BT_CONNECTED;
+
 	return chan;
 }
 
-- 
1.7.9.5


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

* [PATCHv3 06/18] Bluetooth: A2MP: Definitions for A2MP commands
  2012-05-24 11:38 ` [PATCHv3 00/18] Bluetooth A2MP implementation Andrei Emeltchenko
                     ` (4 preceding siblings ...)
  2012-05-24 11:38   ` [PATCHv3 05/18] Bluetooth: A2MP: Add chan callbacks Andrei Emeltchenko
@ 2012-05-24 11:38   ` Andrei Emeltchenko
  2012-05-24 11:38   ` [PATCHv3 07/18] Bluetooth: A2MP: Define A2MP status codes Andrei Emeltchenko
                     ` (11 subsequent siblings)
  17 siblings, 0 replies; 104+ messages in thread
From: Andrei Emeltchenko @ 2012-05-24 11:38 UTC (permalink / raw)
  To: linux-bluetooth

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

Define A2MP command IDs and packet structures.

Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
 include/net/bluetooth/a2mp.h |   73 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 73 insertions(+)

diff --git a/include/net/bluetooth/a2mp.h b/include/net/bluetooth/a2mp.h
index 654df60..7cbeb91 100644
--- a/include/net/bluetooth/a2mp.h
+++ b/include/net/bluetooth/a2mp.h
@@ -31,6 +31,79 @@ struct a2mp_cmd {
 	__u8	data[0];
 } __packed;
 
+/* A2MP command codes */
+#define A2MP_COMMAND_REJ         0x01
+struct a2mp_cmd_rej {
+	__le16	reason;
+	__u8	data[0];
+} __packed;
+
+#define A2MP_DISCOVER_REQ        0x02
+struct a2mp_discov_req {
+	__le16	mtu;
+	__le16	ext_feat;
+} __packed;
+
+struct a2mp_cl {
+	__u8	id;
+	__u8	type;
+	__u8	status;
+} __packed;
+
+#define A2MP_DISCOVER_RSP        0x03
+struct a2mp_discov_rsp {
+	__le16     mtu;
+	__le16     ext_feat;
+	struct a2mp_cl cl[0];
+} __packed;
+
+#define A2MP_CHANGE_NOTIFY       0x04
+#define A2MP_CHANGE_RSP          0x05
+
+#define A2MP_GETINFO_REQ         0x06
+struct a2mp_info_req {
+	__u8       id;
+} __packed;
+
+#define A2MP_GETINFO_RSP         0x07
+struct a2mp_info_rsp {
+	__u8	id;
+	__u8	status;
+	__le32	total_bw;
+	__le32	max_bw;
+	__le32	min_latency;
+	__le16	pal_cap;
+	__le16	assoc_size;
+} __packed;
+
+#define A2MP_GETAMPASSOC_REQ     0x08
+struct a2mp_amp_assoc_req {
+	__u8	id;
+} __packed;
+
+#define A2MP_GETAMPASSOC_RSP     0x09
+struct a2mp_amp_assoc_rsp {
+	__u8	id;
+	__u8	status;
+	__u8	amp_assoc[0];
+} __packed;
+
+#define A2MP_CREATEPHYSLINK_REQ  0x0A
+#define A2MP_DISCONNPHYSLINK_REQ 0x0C
+struct a2mp_physlink_req {
+	__u8	local_id;
+	__u8	remote_id;
+	__u8	amp_assoc[0];
+} __packed;
+
+#define A2MP_CREATEPHYSLINK_RSP  0x0B
+#define A2MP_DISCONNPHYSLINK_RSP 0x0D
+struct a2mp_physlink_rsp {
+	__u8	local_id;
+	__u8	remote_id;
+	__u8	status;
+} __packed;
+
 void amp_mgr_get(struct amp_mgr *mgr);
 int amp_mgr_put(struct amp_mgr *mgr);
 
-- 
1.7.9.5


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

* [PATCHv3 07/18] Bluetooth: A2MP: Define A2MP status codes
  2012-05-24 11:38 ` [PATCHv3 00/18] Bluetooth A2MP implementation Andrei Emeltchenko
                     ` (5 preceding siblings ...)
  2012-05-24 11:38   ` [PATCHv3 06/18] Bluetooth: A2MP: Definitions for A2MP commands Andrei Emeltchenko
@ 2012-05-24 11:38   ` Andrei Emeltchenko
  2012-05-24 11:38   ` [PATCHv3 08/18] Bluetooth: A2MP: Process A2MP messages Andrei Emeltchenko
                     ` (10 subsequent siblings)
  17 siblings, 0 replies; 104+ messages in thread
From: Andrei Emeltchenko @ 2012-05-24 11:38 UTC (permalink / raw)
  To: linux-bluetooth

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

A2MP status codes copied from Bluez patch sent by Peter Krystad
<pkrystad@codeaurora.org>.

Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
 include/net/bluetooth/a2mp.h |   10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/include/net/bluetooth/a2mp.h b/include/net/bluetooth/a2mp.h
index 7cbeb91..391acd7 100644
--- a/include/net/bluetooth/a2mp.h
+++ b/include/net/bluetooth/a2mp.h
@@ -104,6 +104,16 @@ struct a2mp_physlink_rsp {
 	__u8	status;
 } __packed;
 
+/* A2MP response status */
+#define A2MP_STATUS_SUCCESS			0x00
+#define A2MP_STATUS_INVALID_CTRL_ID		0x01
+#define A2MP_STATUS_UNABLE_START_LINK_CREATION	0x02
+#define A2MP_STATUS_NO_PHYSICAL_LINK_EXISTS	0x02
+#define A2MP_STATUS_COLLISION_OCCURED		0x03
+#define A2MP_STATUS_DISCONN_REQ_RECVD		0x04
+#define A2MP_STATUS_PHYS_LINK_EXISTS		0x05
+#define A2MP_STATUS_SECURITY_VIOLATION		0x06
+
 void amp_mgr_get(struct amp_mgr *mgr);
 int amp_mgr_put(struct amp_mgr *mgr);
 
-- 
1.7.9.5


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

* [PATCHv3 08/18] Bluetooth: A2MP: Process A2MP messages
  2012-05-24 11:38 ` [PATCHv3 00/18] Bluetooth A2MP implementation Andrei Emeltchenko
                     ` (6 preceding siblings ...)
  2012-05-24 11:38   ` [PATCHv3 07/18] Bluetooth: A2MP: Define A2MP status codes Andrei Emeltchenko
@ 2012-05-24 11:38   ` Andrei Emeltchenko
  2012-05-24 11:38   ` [PATCHv3 09/18] Bluetooth: A2MP: Process A2MP Command Reject Andrei Emeltchenko
                     ` (9 subsequent siblings)
  17 siblings, 0 replies; 104+ messages in thread
From: Andrei Emeltchenko @ 2012-05-24 11:38 UTC (permalink / raw)
  To: linux-bluetooth

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

Implement basic processing for AMP Manager Protocol (A2MP).

Example below shows processing unrecognized command.
...
> ACL data: handle 11 flags 0x02 dlen 12
    A2MP: code 0x00 ident 3 len 0
< ACL data: handle 11 flags 0x00 dlen 14
    A2MP: Command Reject: reason (0) - Command not recognized
...

Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
 net/bluetooth/a2mp.c |   65 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 65 insertions(+)

diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c
index eb98541..92b7671 100644
--- a/net/bluetooth/a2mp.c
+++ b/net/bluetooth/a2mp.c
@@ -63,6 +63,70 @@ static void a2mp_send(struct amp_mgr *mgr, u8 code, u8 ident, u16 len,
 	kfree(cmd);
 }
 
+/* Handle A2MP signalling */
+static int a2mp_chan_recv_cb(void *data, struct sk_buff *skb)
+{
+	struct a2mp_cmd *hdr = (struct a2mp_cmd *) skb->data;
+	struct amp_mgr *mgr = data;
+	int err = 0;
+
+	amp_mgr_get(mgr);
+
+	while (skb->len >= sizeof(*hdr)) {
+		struct a2mp_cmd *hdr = (struct a2mp_cmd *) skb->data;
+		u16 len = le16_to_cpu(hdr->len);
+
+		BT_DBG("code 0x%02x id %d len %d", hdr->code, hdr->ident, len);
+
+		skb_pull(skb, sizeof(*hdr));
+
+		if (len > skb->len || !hdr->ident) {
+			err = -EINVAL;
+			break;
+		}
+
+		mgr->ident = hdr->ident;
+
+		switch (hdr->code) {
+		case A2MP_COMMAND_REJ:
+		case A2MP_DISCOVER_REQ:
+		case A2MP_CHANGE_NOTIFY:
+		case A2MP_GETINFO_REQ:
+		case A2MP_GETAMPASSOC_REQ:
+		case A2MP_CREATEPHYSLINK_REQ:
+		case A2MP_DISCONNPHYSLINK_REQ:
+		case A2MP_CHANGE_RSP:
+		case A2MP_DISCOVER_RSP:
+		case A2MP_GETINFO_RSP:
+		case A2MP_GETAMPASSOC_RSP:
+		case A2MP_CREATEPHYSLINK_RSP:
+		case A2MP_DISCONNPHYSLINK_RSP:
+		default:
+			BT_ERR("Unknown A2MP sig cmd 0x%2.2x", hdr->code);
+			err = -EINVAL;
+			break;
+		}
+	}
+
+	if (err) {
+		struct a2mp_cmd_rej rej;
+		rej.reason = cpu_to_le16(0);
+
+		BT_DBG("Send A2MP Rej: cmd 0x%2.2x err %d", hdr->code, err);
+
+		a2mp_send(mgr, A2MP_COMMAND_REJ, hdr->ident, sizeof(rej),
+			  &rej);
+	}
+
+	/* Always free skb and return success error code to prevent
+	   from sending L2CAP Disconnect over A2MP channel */
+	kfree_skb(skb);
+
+	amp_mgr_put(mgr);
+
+	return 0;
+}
+
 static void a2mp_chan_state_change_cb(void *data, int state)
 {
 	struct amp_mgr *mgr = data;
@@ -100,6 +164,7 @@ static struct sk_buff *a2mp_chan_alloc_skb_cb(struct l2cap_chan *chan,
 
 static struct l2cap_ops a2mp_chan_ops = {
 	.name = "L2CAP A2MP channel",
+	.recv = a2mp_chan_recv_cb,
 	.state_change = a2mp_chan_state_change_cb,
 	.close = a2mp_chan_close_cb,
 	.alloc_skb = a2mp_chan_alloc_skb_cb,
-- 
1.7.9.5


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

* [PATCHv3 09/18] Bluetooth: A2MP: Process A2MP Command Reject
  2012-05-24 11:38 ` [PATCHv3 00/18] Bluetooth A2MP implementation Andrei Emeltchenko
                     ` (7 preceding siblings ...)
  2012-05-24 11:38   ` [PATCHv3 08/18] Bluetooth: A2MP: Process A2MP messages Andrei Emeltchenko
@ 2012-05-24 11:38   ` Andrei Emeltchenko
  2012-05-24 11:38   ` [PATCHv3 10/18] Bluetooth: A2MP: Process A2MP Discover Request Andrei Emeltchenko
                     ` (8 subsequent siblings)
  17 siblings, 0 replies; 104+ messages in thread
From: Andrei Emeltchenko @ 2012-05-24 11:38 UTC (permalink / raw)
  To: linux-bluetooth

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

Placeholder for future A2MP Command Reject handler.

Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
 net/bluetooth/a2mp.c |   19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c
index 92b7671..4137f9b 100644
--- a/net/bluetooth/a2mp.c
+++ b/net/bluetooth/a2mp.c
@@ -63,6 +63,22 @@ static void a2mp_send(struct amp_mgr *mgr, u8 code, u8 ident, u16 len,
 	kfree(cmd);
 }
 
+/* Processing A2MP messages */
+static int a2mp_command_rej(struct amp_mgr *mgr, struct sk_buff *skb,
+			    struct a2mp_cmd *hdr)
+{
+	struct a2mp_cmd_rej *rej = (struct a2mp_cmd_rej *) skb->data;
+
+	if (le16_to_cpu(hdr->len) < sizeof(*rej))
+		return -EINVAL;
+
+	BT_DBG("ident %d reason %d", hdr->ident, le16_to_cpu(rej->reason));
+
+	skb_pull(skb, sizeof(*rej));
+
+	return 0;
+}
+
 /* Handle A2MP signalling */
 static int a2mp_chan_recv_cb(void *data, struct sk_buff *skb)
 {
@@ -89,6 +105,9 @@ static int a2mp_chan_recv_cb(void *data, struct sk_buff *skb)
 
 		switch (hdr->code) {
 		case A2MP_COMMAND_REJ:
+			a2mp_command_rej(mgr, skb, hdr);
+			break;
+
 		case A2MP_DISCOVER_REQ:
 		case A2MP_CHANGE_NOTIFY:
 		case A2MP_GETINFO_REQ:
-- 
1.7.9.5


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

* [PATCHv3 10/18] Bluetooth: A2MP: Process A2MP Discover Request
  2012-05-24 11:38 ` [PATCHv3 00/18] Bluetooth A2MP implementation Andrei Emeltchenko
                     ` (8 preceding siblings ...)
  2012-05-24 11:38   ` [PATCHv3 09/18] Bluetooth: A2MP: Process A2MP Command Reject Andrei Emeltchenko
@ 2012-05-24 11:38   ` Andrei Emeltchenko
  2012-05-25 12:19     ` Gustavo Padovan
  2012-05-24 11:38   ` [PATCHv3 11/18] Bluetooth: A2MP: Process A2MP Change Notify Andrei Emeltchenko
                     ` (7 subsequent siblings)
  17 siblings, 1 reply; 104+ messages in thread
From: Andrei Emeltchenko @ 2012-05-24 11:38 UTC (permalink / raw)
  To: linux-bluetooth

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

Adds helper functions to count HCI devs and process A2MP Discover
Request, code makes sure that first controller in the list is
BREDR one. Trace is shown below:

...
> ACL data: handle 11 flags 0x02 dlen 16
    A2MP: Discover req: mtu/mps 670 mask: 0x0000
< ACL data: handle 11 flags 0x00 dlen 22
    A2MP: Discover rsp: mtu/mps 670 mask: 0x0000
      Controller list:
        id 0 type 0 (BR-EDR) status 0x01 (Bluetooth only)
        id 1 type 1 (802.11 AMP) status 0x01 (Bluetooth only)
...

Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
 include/net/bluetooth/a2mp.h     |    2 +
 include/net/bluetooth/hci.h      |    3 ++
 include/net/bluetooth/hci_core.h |   13 ++++++
 net/bluetooth/a2mp.c             |   85 ++++++++++++++++++++++++++++++++++++++
 4 files changed, 103 insertions(+)

diff --git a/include/net/bluetooth/a2mp.h b/include/net/bluetooth/a2mp.h
index 391acd7..96f9cc2 100644
--- a/include/net/bluetooth/a2mp.h
+++ b/include/net/bluetooth/a2mp.h
@@ -15,6 +15,8 @@
 #ifndef __A2MP_H
 #define __A2MP_H
 
+#define A2MP_FEAT_EXT	0x8000
+
 struct amp_mgr {
 	struct l2cap_conn	*l2cap_conn;
 	struct l2cap_chan	*a2mp_chan;
diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index edb6639..158f403 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -58,6 +58,9 @@
 #define HCI_BREDR	0x00
 #define HCI_AMP		0x01
 
+/* First BR/EDR Controller shall have ID = 0 */
+#define HCI_BREDR_ID	0
+
 /* HCI device quirks */
 enum {
 	HCI_QUIRK_RESET_ON_CLOSE,
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 6e64b76..20fd573 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -641,6 +641,19 @@ static inline void hci_set_drvdata(struct hci_dev *hdev, void *data)
 	dev_set_drvdata(&hdev->dev, data);
 }
 
+/* hci_dev_list shall be locked */
+static inline uint8_t __hci_num_ctrl(void)
+{
+	uint8_t count = 0;
+	struct list_head *p;
+
+	list_for_each(p, &hci_dev_list) {
+		count++;
+	}
+
+	return count;
+}
+
 struct hci_dev *hci_dev_get(int index);
 struct hci_dev *hci_get_route(bdaddr_t *src, bdaddr_t *dst);
 
diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c
index 4137f9b..ac095ac 100644
--- a/net/bluetooth/a2mp.c
+++ b/net/bluetooth/a2mp.c
@@ -63,6 +63,36 @@ static void a2mp_send(struct amp_mgr *mgr, u8 code, u8 ident, u16 len,
 	kfree(cmd);
 }
 
+static inline void __a2mp_cl_bredr(struct a2mp_cl *cl)
+{
+	cl->id = 0;
+	cl->type = 0;
+	cl->status = 1;
+}
+
+/* hci_dev_list shall be locked */
+static void __a2mp_add_cl(struct amp_mgr *mgr, struct a2mp_cl *cl, u8 num_ctrl)
+{
+	int i = 0;
+	struct hci_dev *hdev;
+
+	__a2mp_cl_bredr(cl);
+
+	list_for_each_entry(hdev, &hci_dev_list, list) {
+		/* Iterate through AMP controllers */
+		if (hdev->id == HCI_BREDR_ID)
+			continue;
+
+		/* Starting from second entry */
+		if (++i >= num_ctrl)
+			return;
+
+		cl[i].id = hdev->id;
+		cl[i].type = hdev->amp_type;
+		cl[i].status = hdev->amp_status;
+	}
+}
+
 /* Processing A2MP messages */
 static int a2mp_command_rej(struct amp_mgr *mgr, struct sk_buff *skb,
 			    struct a2mp_cmd *hdr)
@@ -79,6 +109,58 @@ static int a2mp_command_rej(struct amp_mgr *mgr, struct sk_buff *skb,
 	return 0;
 }
 
+static int a2mp_discover_req(struct amp_mgr *mgr, struct sk_buff *skb,
+			     struct a2mp_cmd *hdr)
+{
+	struct a2mp_discov_req *req = (struct a2mp_discov_req *) skb->data;
+	u16 len = le16_to_cpu(hdr->len);
+	struct a2mp_discov_rsp *rsp;
+	u16 ext_feat;
+	u8 num_ctrl;
+
+	if (len < sizeof(*req))
+		return -EINVAL;
+
+	skb_pull(skb, sizeof(*req));
+
+	ext_feat = le16_to_cpu(req->ext_feat);
+
+	BT_DBG("mtu %d efm 0x%4.4x", le16_to_cpu(req->mtu), ext_feat);
+
+	/* check that packet is not broken for now */
+	while (ext_feat & A2MP_FEAT_EXT) {
+		if (len < sizeof(ext_feat))
+			return -EINVAL;
+
+		ext_feat = get_unaligned_le16(skb->data);
+		BT_DBG("efm 0x%4.4x", ext_feat);
+		len -= sizeof(ext_feat);
+		skb_pull(skb, sizeof(ext_feat));
+	}
+
+	read_lock(&hci_dev_list_lock);
+
+	num_ctrl = __hci_num_ctrl();
+	len = num_ctrl * sizeof(struct a2mp_cl) + sizeof(*rsp);
+	rsp = kmalloc(len, GFP_ATOMIC);
+	if (!rsp) {
+		read_unlock(&hci_dev_list_lock);
+		return -ENOMEM;
+	}
+
+	rsp->mtu = cpu_to_le16(L2CAP_A2MP_DEFAULT_MTU);
+	rsp->ext_feat = 0;
+
+	__a2mp_add_cl(mgr, rsp->cl, num_ctrl);
+
+	read_unlock(&hci_dev_list_lock);
+
+	a2mp_send(mgr, A2MP_DISCOVER_RSP, hdr->ident, len, rsp);
+
+	kfree(rsp);
+	return 0;
+}
+
 /* Handle A2MP signalling */
 static int a2mp_chan_recv_cb(void *data, struct sk_buff *skb)
 {
@@ -109,6 +191,9 @@ static int a2mp_chan_recv_cb(void *data, struct sk_buff *skb)
 			break;
 
 		case A2MP_DISCOVER_REQ:
+			err = a2mp_discover_req(mgr, skb, hdr);
+			break;
+
 		case A2MP_CHANGE_NOTIFY:
 		case A2MP_GETINFO_REQ:
 		case A2MP_GETAMPASSOC_REQ:
-- 
1.7.9.5


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

* [PATCHv3 11/18] Bluetooth: A2MP: Process A2MP Change Notify
  2012-05-24 11:38 ` [PATCHv3 00/18] Bluetooth A2MP implementation Andrei Emeltchenko
                     ` (9 preceding siblings ...)
  2012-05-24 11:38   ` [PATCHv3 10/18] Bluetooth: A2MP: Process A2MP Discover Request Andrei Emeltchenko
@ 2012-05-24 11:38   ` Andrei Emeltchenko
  2012-05-25 12:29     ` Gustavo Padovan
  2012-05-24 11:38   ` [PATCHv3 12/18] Bluetooth: A2MP: Process A2MP Get Info Request Andrei Emeltchenko
                     ` (6 subsequent siblings)
  17 siblings, 1 reply; 104+ messages in thread
From: Andrei Emeltchenko @ 2012-05-24 11:38 UTC (permalink / raw)
  To: linux-bluetooth

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

Placeholder for A2MP Change Notify handler.

Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
 net/bluetooth/a2mp.c |   19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c
index ac095ac..d60be75 100644
--- a/net/bluetooth/a2mp.c
+++ b/net/bluetooth/a2mp.c
@@ -161,6 +161,22 @@ static int a2mp_discover_req(struct amp_mgr *mgr, struct sk_buff *skb,
 	return 0;
 }
 
+static int a2mp_change_notify(struct amp_mgr *mgr, struct sk_buff *skb,
+			      struct a2mp_cmd *hdr)
+{
+	struct a2mp_cl *cl = (struct a2mp_cl *) skb->data;
+
+	while (skb->len >= sizeof(*cl)) {
+		BT_DBG("Controller id %d type %d status %d", cl->id, cl->type,
+		       cl->status);
+		cl = (struct a2mp_cl *) skb_pull(skb, sizeof(*cl));
+	}
+
+	/* TODO send A2MP_CHANGE_RSP */
+
+	return 0;
+}
+
 /* Handle A2MP signalling */
 static int a2mp_chan_recv_cb(void *data, struct sk_buff *skb)
 {
@@ -195,6 +211,9 @@ static int a2mp_chan_recv_cb(void *data, struct sk_buff *skb)
 			break;
 
 		case A2MP_CHANGE_NOTIFY:
+			err = a2mp_change_notify(mgr, skb, hdr);
+			break;
+
 		case A2MP_GETINFO_REQ:
 		case A2MP_GETAMPASSOC_REQ:
 		case A2MP_CREATEPHYSLINK_REQ:
-- 
1.7.9.5


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

* [PATCHv3 12/18] Bluetooth: A2MP: Process A2MP Get Info Request
  2012-05-24 11:38 ` [PATCHv3 00/18] Bluetooth A2MP implementation Andrei Emeltchenko
                     ` (10 preceding siblings ...)
  2012-05-24 11:38   ` [PATCHv3 11/18] Bluetooth: A2MP: Process A2MP Change Notify Andrei Emeltchenko
@ 2012-05-24 11:38   ` Andrei Emeltchenko
  2012-05-24 11:38   ` [PATCHv3 13/18] Bluetooth: A2MP: Process A2MP Get AMP Assoc Request Andrei Emeltchenko
                     ` (5 subsequent siblings)
  17 siblings, 0 replies; 104+ messages in thread
From: Andrei Emeltchenko @ 2012-05-24 11:38 UTC (permalink / raw)
  To: linux-bluetooth

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

Process A2MP Get Info Request.
Example of trace log for invalid controller id is shown below:

...
> ACL data: handle 11 flags 0x02 dlen 13
    A2MP: Get Info req: id 238
< ACL data: handle 11 flags 0x00 dlen 30
    A2MP: Get Info rsp: id 238 status (1) Invalid Controller ID
...

Note that If the Status field is set to Invalid Controller ID all subsequent
fields in the AMP Get Info Response shall be ignored by the receiver.

Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
 net/bluetooth/a2mp.c |   37 +++++++++++++++++++++++++++++++++++++
 1 file changed, 37 insertions(+)

diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c
index d60be75..d636c0c 100644
--- a/net/bluetooth/a2mp.c
+++ b/net/bluetooth/a2mp.c
@@ -177,6 +177,40 @@ static int a2mp_change_notify(struct amp_mgr *mgr, struct sk_buff *skb,
 	return 0;
 }
 
+static int a2mp_getinfo_req(struct amp_mgr *mgr, struct sk_buff *skb,
+			    struct a2mp_cmd *hdr)
+{
+	struct a2mp_info_req *req  = (struct a2mp_info_req *) skb->data;
+	struct a2mp_info_rsp rsp;
+	struct hci_dev *hdev;
+
+	if (le16_to_cpu(hdr->len) < sizeof(*req))
+		return -EINVAL;
+
+	BT_DBG("id %d", req->id);
+
+	rsp.id = req->id;
+	rsp.status = A2MP_STATUS_INVALID_CTRL_ID;
+
+	hdev = hci_dev_get(req->id);
+	if (hdev && hdev->amp_type != HCI_BREDR) {
+		rsp.status = 0;
+		rsp.total_bw = cpu_to_le32(hdev->amp_total_bw);
+		rsp.max_bw = cpu_to_le32(hdev->amp_max_bw);
+		rsp.min_latency = cpu_to_le32(hdev->amp_min_latency);
+		rsp.pal_cap = cpu_to_le16(hdev->amp_pal_cap);
+		rsp.assoc_size = cpu_to_le16(hdev->amp_assoc_size);
+	}
+
+	if (hdev)
+		hci_dev_put(hdev);
+
+	a2mp_send(mgr, A2MP_GETINFO_RSP, hdr->ident, sizeof(rsp), &rsp);
+
+	skb_pull(skb, sizeof(*req));
+	return 0;
+}
+
 /* Handle A2MP signalling */
 static int a2mp_chan_recv_cb(void *data, struct sk_buff *skb)
 {
@@ -215,6 +249,9 @@ static int a2mp_chan_recv_cb(void *data, struct sk_buff *skb)
 			break;
 
 		case A2MP_GETINFO_REQ:
+			err = a2mp_getinfo_req(mgr, skb, hdr);
+			break;
+
 		case A2MP_GETAMPASSOC_REQ:
 		case A2MP_CREATEPHYSLINK_REQ:
 		case A2MP_DISCONNPHYSLINK_REQ:
-- 
1.7.9.5


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

* [PATCHv3 13/18] Bluetooth: A2MP: Process A2MP Get AMP Assoc Request
  2012-05-24 11:38 ` [PATCHv3 00/18] Bluetooth A2MP implementation Andrei Emeltchenko
                     ` (11 preceding siblings ...)
  2012-05-24 11:38   ` [PATCHv3 12/18] Bluetooth: A2MP: Process A2MP Get Info Request Andrei Emeltchenko
@ 2012-05-24 11:38   ` Andrei Emeltchenko
  2012-05-24 11:38   ` [PATCHv3 14/18] Bluetooth: A2MP: Process A2MP Create Physlink Request Andrei Emeltchenko
                     ` (4 subsequent siblings)
  17 siblings, 0 replies; 104+ messages in thread
From: Andrei Emeltchenko @ 2012-05-24 11:38 UTC (permalink / raw)
  To: linux-bluetooth

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

Example trace when receiving AMP Assoc Request with wrong AMP id.
...
> ACL data: handle 11 flags 0x02 dlen 13
    A2MP: Get AMP Assoc req: id 238
< ACL data: handle 11 flags 0x00 dlen 14
    A2MP: Get AMP Assoc rsp: id 238 status (1) Invalid Controller ID
      assoc data:
...

Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
 net/bluetooth/a2mp.c |   36 ++++++++++++++++++++++++++++++++++++
 1 file changed, 36 insertions(+)

diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c
index d636c0c..c98a402 100644
--- a/net/bluetooth/a2mp.c
+++ b/net/bluetooth/a2mp.c
@@ -211,6 +211,39 @@ static int a2mp_getinfo_req(struct amp_mgr *mgr, struct sk_buff *skb,
 	return 0;
 }
 
+static int a2mp_getampassoc_req(struct amp_mgr *mgr, struct sk_buff *skb,
+				struct a2mp_cmd *hdr)
+{
+	struct a2mp_amp_assoc_req *req =
+				(struct a2mp_amp_assoc_req *) skb->data;
+	struct hci_dev *hdev;
+
+	if (le16_to_cpu(hdr->len) < sizeof(*req))
+		return -EINVAL;
+
+	BT_DBG("id %d", req->id);
+
+	hdev = hci_dev_get(req->id);
+	if (!hdev || hdev->amp_type == HCI_BREDR) {
+		struct a2mp_amp_assoc_rsp rsp;
+		rsp.id = req->id;
+		rsp.status = A2MP_STATUS_INVALID_CTRL_ID;
+
+		a2mp_send(mgr, A2MP_GETAMPASSOC_RSP, hdr->ident, sizeof(rsp),
+			  &rsp);
+		goto clean;
+	}
+
+	/* Placeholder for HCI Read AMP Assoc */
+
+clean:
+	if (hdev)
+		hci_dev_put(hdev);
+
+	skb_pull(skb, sizeof(*req));
+	return 0;
+}
+
 /* Handle A2MP signalling */
 static int a2mp_chan_recv_cb(void *data, struct sk_buff *skb)
 {
@@ -253,6 +286,9 @@ static int a2mp_chan_recv_cb(void *data, struct sk_buff *skb)
 			break;
 
 		case A2MP_GETAMPASSOC_REQ:
+			err = a2mp_getampassoc_req(mgr, skb, hdr);
+			break;
+
 		case A2MP_CREATEPHYSLINK_REQ:
 		case A2MP_DISCONNPHYSLINK_REQ:
 		case A2MP_CHANGE_RSP:
-- 
1.7.9.5


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

* [PATCHv3 14/18] Bluetooth: A2MP: Process A2MP Create Physlink Request
  2012-05-24 11:38 ` [PATCHv3 00/18] Bluetooth A2MP implementation Andrei Emeltchenko
                     ` (12 preceding siblings ...)
  2012-05-24 11:38   ` [PATCHv3 13/18] Bluetooth: A2MP: Process A2MP Get AMP Assoc Request Andrei Emeltchenko
@ 2012-05-24 11:38   ` Andrei Emeltchenko
  2012-05-24 11:38   ` [PATCHv3 15/18] Bluetooth: A2MP: Process A2MP Disc " Andrei Emeltchenko
                     ` (3 subsequent siblings)
  17 siblings, 0 replies; 104+ messages in thread
From: Andrei Emeltchenko @ 2012-05-24 11:38 UTC (permalink / raw)
  To: linux-bluetooth

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

Placeholder for A2MP Create Physlink Request.
Handles requests with invalid controler id as shown below:

...
> ACL data: handle 11 flags 0x02 dlen 50
    A2MP: Create Physical Link req: local id 1 remote id 85
      Assoc data:
        <skipped>
< ACL data: handle 11 flags 0x00 dlen 15
    A2MP: Create Physical Link rsp: local id 85 remote id 1 status 1
      Invalid Controller ID
...

Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
 net/bluetooth/a2mp.c |   39 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 39 insertions(+)

diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c
index c98a402..ae4e38b 100644
--- a/net/bluetooth/a2mp.c
+++ b/net/bluetooth/a2mp.c
@@ -244,6 +244,42 @@ clean:
 	return 0;
 }
 
+static int a2mp_createphyslink_req(struct amp_mgr *mgr, struct sk_buff *skb,
+				   struct a2mp_cmd *hdr)
+{
+	struct a2mp_physlink_req *req = (struct a2mp_physlink_req *) skb->data;
+	struct a2mp_physlink_rsp rsp;
+	struct hci_dev *hdev;
+
+	if (le16_to_cpu(hdr->len) < sizeof(*req))
+		return -EINVAL;
+
+	BT_DBG("local_id %d, remote_id %d", req->local_id, req->remote_id);
+
+	rsp.local_id = req->remote_id;
+	rsp.remote_id = req->local_id;
+
+	hdev = hci_dev_get(req->remote_id);
+	if (!hdev || hdev->amp_type != HCI_AMP) {
+		rsp.status = A2MP_STATUS_INVALID_CTRL_ID;
+		goto send_rsp;
+	}
+
+	/* TODO process physlink create */
+
+	rsp.status = A2MP_STATUS_SUCCESS;
+
+send_rsp:
+	if (hdev)
+		hci_dev_put(hdev);
+
+	a2mp_send(mgr, A2MP_CREATEPHYSLINK_RSP, hdr->ident, sizeof(rsp),
+		  &rsp);
+
+	skb_pull(skb, le16_to_cpu(hdr->len));
+	return 0;
+}
+
 /* Handle A2MP signalling */
 static int a2mp_chan_recv_cb(void *data, struct sk_buff *skb)
 {
@@ -290,6 +326,9 @@ static int a2mp_chan_recv_cb(void *data, struct sk_buff *skb)
 			break;
 
 		case A2MP_CREATEPHYSLINK_REQ:
+			err = a2mp_createphyslink_req(mgr, skb, hdr);
+			break;
+
 		case A2MP_DISCONNPHYSLINK_REQ:
 		case A2MP_CHANGE_RSP:
 		case A2MP_DISCOVER_RSP:
-- 
1.7.9.5


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

* [PATCHv3 15/18] Bluetooth: A2MP: Process A2MP Disc Physlink Request
  2012-05-24 11:38 ` [PATCHv3 00/18] Bluetooth A2MP implementation Andrei Emeltchenko
                     ` (13 preceding siblings ...)
  2012-05-24 11:38   ` [PATCHv3 14/18] Bluetooth: A2MP: Process A2MP Create Physlink Request Andrei Emeltchenko
@ 2012-05-24 11:38   ` Andrei Emeltchenko
  2012-05-24 11:38   ` [PATCHv3 16/18] Bluetooth: A2MP: Process A2MP Command Responses Andrei Emeltchenko
                     ` (2 subsequent siblings)
  17 siblings, 0 replies; 104+ messages in thread
From: Andrei Emeltchenko @ 2012-05-24 11:38 UTC (permalink / raw)
  To: linux-bluetooth

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

Placeholder for A2MP Disconnect Physlink Request.

Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
 net/bluetooth/a2mp.c |   36 ++++++++++++++++++++++++++++++++++++
 1 file changed, 36 insertions(+)

diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c
index ae4e38b..16598f9 100644
--- a/net/bluetooth/a2mp.c
+++ b/net/bluetooth/a2mp.c
@@ -280,6 +280,39 @@ send_rsp:
 	return 0;
 }
 
+static int a2mp_discphyslink_req(struct amp_mgr *mgr, struct sk_buff *skb,
+				 struct a2mp_cmd *hdr)
+{
+	struct a2mp_physlink_req *req = (struct a2mp_physlink_req *) skb->data;
+	struct a2mp_physlink_rsp rsp;
+	struct hci_dev *hdev;
+
+	if (le16_to_cpu(hdr->len) < sizeof(*req))
+		return -EINVAL;
+
+	BT_DBG("local_id %d remote_id %d", req->local_id, req->remote_id);
+
+	rsp.local_id = req->remote_id;
+	rsp.remote_id = req->local_id;
+	rsp.status = A2MP_STATUS_SUCCESS;
+
+	hdev = hci_dev_get(req->local_id);
+	if (!hdev) {
+		rsp.status = A2MP_STATUS_INVALID_CTRL_ID;
+		goto send_rsp;
+	}
+
+	/* TODO Disconnect Phys Link here */
+
+	hci_dev_put(hdev);
+
+send_rsp:
+	a2mp_send(mgr, A2MP_DISCONNPHYSLINK_RSP, hdr->ident, sizeof(rsp), &rsp);
+
+	skb_pull(skb, sizeof(*req));
+	return 0;
+}
+
 /* Handle A2MP signalling */
 static int a2mp_chan_recv_cb(void *data, struct sk_buff *skb)
 {
@@ -330,6 +363,9 @@ static int a2mp_chan_recv_cb(void *data, struct sk_buff *skb)
 			break;
 
 		case A2MP_DISCONNPHYSLINK_REQ:
+			err = a2mp_discphyslink_req(mgr, skb, hdr);
+			break;
+
 		case A2MP_CHANGE_RSP:
 		case A2MP_DISCOVER_RSP:
 		case A2MP_GETINFO_RSP:
-- 
1.7.9.5


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

* [PATCHv3 16/18] Bluetooth: A2MP: Process A2MP Command Responses
  2012-05-24 11:38 ` [PATCHv3 00/18] Bluetooth A2MP implementation Andrei Emeltchenko
                     ` (14 preceding siblings ...)
  2012-05-24 11:38   ` [PATCHv3 15/18] Bluetooth: A2MP: Process A2MP Disc " Andrei Emeltchenko
@ 2012-05-24 11:38   ` Andrei Emeltchenko
  2012-05-24 11:38   ` [PATCHv3 17/18] Bluetooth: A2MP: Handling fixed channels Andrei Emeltchenko
  2012-05-24 11:38   ` [PATCHv3 18/18] Bluetooth: A2MP: Manage incoming connections Andrei Emeltchenko
  17 siblings, 0 replies; 104+ messages in thread
From: Andrei Emeltchenko @ 2012-05-24 11:38 UTC (permalink / raw)
  To: linux-bluetooth

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

Process A2MP responses, print cmd code and ident for now.

Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
 net/bluetooth/a2mp.c |   12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c
index 16598f9..a454f8b 100644
--- a/net/bluetooth/a2mp.c
+++ b/net/bluetooth/a2mp.c
@@ -313,6 +313,15 @@ send_rsp:
 	return 0;
 }
 
+static inline int a2mp_cmd_rsp(struct amp_mgr *mgr, struct sk_buff *skb,
+			       struct a2mp_cmd *hdr)
+{
+	BT_DBG("ident %d code %d", hdr->ident, hdr->code);
+
+	skb_pull(skb, le16_to_cpu(hdr->len));
+	return 0;
+}
+
 /* Handle A2MP signalling */
 static int a2mp_chan_recv_cb(void *data, struct sk_buff *skb)
 {
@@ -372,6 +381,9 @@ static int a2mp_chan_recv_cb(void *data, struct sk_buff *skb)
 		case A2MP_GETAMPASSOC_RSP:
 		case A2MP_CREATEPHYSLINK_RSP:
 		case A2MP_DISCONNPHYSLINK_RSP:
+			err = a2mp_cmd_rsp(mgr, skb, hdr);
+			break;
+
 		default:
 			BT_ERR("Unknown A2MP sig cmd 0x%2.2x", hdr->code);
 			err = -EINVAL;
-- 
1.7.9.5


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

* [PATCHv3 17/18] Bluetooth: A2MP: Handling fixed channels
  2012-05-24 11:38 ` [PATCHv3 00/18] Bluetooth A2MP implementation Andrei Emeltchenko
                     ` (15 preceding siblings ...)
  2012-05-24 11:38   ` [PATCHv3 16/18] Bluetooth: A2MP: Process A2MP Command Responses Andrei Emeltchenko
@ 2012-05-24 11:38   ` Andrei Emeltchenko
  2012-05-24 11:38   ` [PATCHv3 18/18] Bluetooth: A2MP: Manage incoming connections Andrei Emeltchenko
  17 siblings, 0 replies; 104+ messages in thread
From: Andrei Emeltchenko @ 2012-05-24 11:38 UTC (permalink / raw)
  To: linux-bluetooth

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

A2MP fixed channel do not have sk

Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
 include/net/bluetooth/l2cap.h |    1 +
 net/bluetooth/a2mp.c          |    3 +--
 net/bluetooth/l2cap_core.c    |   17 +++++++++++++++++
 3 files changed, 19 insertions(+), 2 deletions(-)

diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index b022329..2fd0afd 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -575,6 +575,7 @@ struct l2cap_conn {
 #define L2CAP_CHAN_RAW			1
 #define L2CAP_CHAN_CONN_LESS		2
 #define L2CAP_CHAN_CONN_ORIENTED	3
+#define L2CAP_CHAN_CONN_FIX_A2MP	4
 
 /* ----- L2CAP socket info ----- */
 #define l2cap_pi(sk) ((struct l2cap_pinfo *) sk)
diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c
index a454f8b..894e53c 100644
--- a/net/bluetooth/a2mp.c
+++ b/net/bluetooth/a2mp.c
@@ -466,8 +466,7 @@ static struct l2cap_chan *a2mp_chan_open(struct l2cap_conn *conn)
 
 	hci_conn_hold(conn->hcon);
 
-	chan->omtu = L2CAP_A2MP_DEFAULT_MTU;
-	chan->imtu = L2CAP_A2MP_DEFAULT_MTU;
+	chan->chan_type = L2CAP_CHAN_CONN_FIX_A2MP;
 	chan->flush_to = L2CAP_DEFAULT_FLUSH_TO;
 
 	chan->ops = &a2mp_chan_ops;
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 275b8f7..3cbdd1d 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -465,6 +465,13 @@ static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
 		chan->omtu = L2CAP_DEFAULT_MTU;
 		break;
 
+	case L2CAP_CHAN_CONN_FIX_A2MP:
+		chan->scid = L2CAP_CID_A2MP;
+		chan->dcid = L2CAP_CID_A2MP;
+		chan->omtu = L2CAP_A2MP_DEFAULT_MTU;
+		chan->imtu = L2CAP_A2MP_DEFAULT_MTU;
+		break;
+
 	default:
 		/* Raw socket can send/recv signalling messages only */
 		chan->scid = L2CAP_CID_SIGNALING;
@@ -1025,6 +1032,11 @@ static void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *c
 		__clear_ack_timer(chan);
 	}
 
+	if (chan->chan_type == L2CAP_CHAN_CONN_FIX_A2MP) {
+		__l2cap_state_change(chan, BT_DISCONN);
+		return;
+	}
+
 	req.dcid = cpu_to_le16(chan->dcid);
 	req.scid = cpu_to_le16(chan->scid);
 	l2cap_send_cmd(conn, l2cap_get_ident(conn),
@@ -1228,6 +1240,11 @@ static void l2cap_conn_ready(struct l2cap_conn *conn)
 
 		l2cap_chan_lock(chan);
 
+		if (chan->chan_type == L2CAP_CHAN_CONN_FIX_A2MP) {
+			l2cap_chan_unlock(chan);
+			continue;
+		}
+
 		if (conn->hcon->type == LE_LINK) {
 			if (smp_conn_security(conn, chan->sec_level))
 				l2cap_chan_ready(chan);
-- 
1.7.9.5


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

* [PATCHv3 18/18] Bluetooth: A2MP: Manage incoming connections
  2012-05-24 11:38 ` [PATCHv3 00/18] Bluetooth A2MP implementation Andrei Emeltchenko
                     ` (16 preceding siblings ...)
  2012-05-24 11:38   ` [PATCHv3 17/18] Bluetooth: A2MP: Handling fixed channels Andrei Emeltchenko
@ 2012-05-24 11:38   ` Andrei Emeltchenko
  17 siblings, 0 replies; 104+ messages in thread
From: Andrei Emeltchenko @ 2012-05-24 11:38 UTC (permalink / raw)
  To: linux-bluetooth

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

Handle incoming A2MP connection by creating AMP manager and
processing A2MP messages.

Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
 include/net/bluetooth/a2mp.h |    4 ++++
 net/bluetooth/a2mp.c         |   16 ++++++++++++++++
 net/bluetooth/l2cap_core.c   |   19 +++++++++++++++----
 3 files changed, 35 insertions(+), 4 deletions(-)

diff --git a/include/net/bluetooth/a2mp.h b/include/net/bluetooth/a2mp.h
index 96f9cc2..6a76e0a 100644
--- a/include/net/bluetooth/a2mp.h
+++ b/include/net/bluetooth/a2mp.h
@@ -15,6 +15,8 @@
 #ifndef __A2MP_H
 #define __A2MP_H
 
+#include <net/bluetooth/l2cap.h>
+
 #define A2MP_FEAT_EXT	0x8000
 
 struct amp_mgr {
@@ -118,5 +120,7 @@ struct a2mp_physlink_rsp {
 
 void amp_mgr_get(struct amp_mgr *mgr);
 int amp_mgr_put(struct amp_mgr *mgr);
+struct l2cap_chan *a2mp_channel_create(struct l2cap_conn *conn,
+				       struct sk_buff *skb);
 
 #endif /* __A2MP_H */
diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c
index 894e53c..2f0172b 100644
--- a/net/bluetooth/a2mp.c
+++ b/net/bluetooth/a2mp.c
@@ -552,3 +552,19 @@ static struct amp_mgr *amp_mgr_create(struct l2cap_conn *conn)
 
 	return mgr;
 }
+
+struct l2cap_chan *a2mp_channel_create(struct l2cap_conn *conn,
+				       struct sk_buff *skb)
+{
+	struct amp_mgr *mgr;
+
+	mgr = amp_mgr_create(conn);
+	if (!mgr) {
+		BT_ERR("Could not create AMP manager");
+		return NULL;
+	}
+
+	BT_DBG("mgr: %p chan %p", mgr, mgr->a2mp_chan);
+
+	return mgr->a2mp_chan;
+}
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 3cbdd1d..2cfbc0c 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -37,6 +37,7 @@
 #include <net/bluetooth/hci_core.h>
 #include <net/bluetooth/l2cap.h>
 #include <net/bluetooth/smp.h>
+#include <net/bluetooth/a2mp.h>
 
 bool disable_ertm;
 
@@ -5175,10 +5176,20 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk
 
 	chan = l2cap_get_chan_by_scid(conn, cid);
 	if (!chan) {
-		BT_DBG("unknown cid 0x%4.4x", cid);
-		/* Drop packet and return */
-		kfree_skb(skb);
-		return 0;
+		if (cid == L2CAP_CID_A2MP) {
+			chan = a2mp_channel_create(conn, skb);
+			if (!chan) {
+				kfree_skb(skb);
+				return 0;
+			}
+
+			l2cap_chan_lock(chan);
+		} else {
+			BT_DBG("unknown cid 0x%4.4x", cid);
+			/* Drop packet and return */
+			kfree_skb(skb);
+			return 0;
+		}
 	}
 
 	BT_DBG("chan %p, len %d", chan, skb->len);
-- 
1.7.9.5


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

* Re: [PATCHv2 19/19] Bluetooth: A2MP: Manage incoming connections
  2012-05-23 23:30     ` Mat Martineau
@ 2012-05-24 11:43       ` Andrei Emeltchenko
  0 siblings, 0 replies; 104+ messages in thread
From: Andrei Emeltchenko @ 2012-05-24 11:43 UTC (permalink / raw)
  To: Mat Martineau; +Cc: linux-bluetooth

Hi Mat,

On Wed, May 23, 2012 at 04:30:39PM -0700, Mat Martineau wrote:
> >+struct l2cap_chan *a2mp_channel_create(struct l2cap_conn *conn,
> >+				       struct sk_buff *skb)
> >+{
> >+	struct amp_mgr *mgr;
> >+
> >+	mgr = amp_mgr_create(conn);
> >+
> >+	BT_DBG("mgr: %p chan %p", mgr, mgr->a2mp_chan);
> >+
> >+	return mgr->a2mp_chan;
> 
> mgr can be NULL.

...

> >	chan = l2cap_get_chan_by_scid(conn, cid);
> >	if (!chan) {
> >-		BT_DBG("unknown cid 0x%4.4x", cid);
> >-		/* Drop packet and return */
> >-		kfree_skb(skb);
> >-		return 0;
> >+		if (cid == L2CAP_CID_A2MP) {
> >+			chan = a2mp_channel_create(conn, skb);
> 
> If amp_mgr_create returned NULL, then you would have to handle NULL
> from a2mp_channel_create too.

I've taken all comment in my v3 patch series.

Best regards 
Andrei Emeltchenko 


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

* Re: [PATCHv1 01/17] Bluetooth: A2MP: Create A2MP channel
  2012-05-24  7:51         ` Andrei Emeltchenko
@ 2012-05-24 15:59           ` Mat Martineau
  2012-05-25  8:09             ` Andrei Emeltchenko
  0 siblings, 1 reply; 104+ messages in thread
From: Mat Martineau @ 2012-05-24 15:59 UTC (permalink / raw)
  To: Andrei Emeltchenko; +Cc: linux-bluetooth, pkrystad


Hi Andrei -

On Thu, 24 May 2012, Andrei Emeltchenko wrote:
> On Wed, May 23, 2012 at 08:44:22AM -0700, Mat Martineau wrote:
>>>>> +static struct l2cap_chan *a2mp_chan_open(struct l2cap_conn *conn)
>>>>> +{
>>>>> +	struct l2cap_chan *chan;
>>>>> +
>>>>> +	chan = l2cap_chan_create();
>>>>> +	if (!chan)
>>>>> +		return NULL;
>>>>> +
>>>>> +	BT_DBG("chan %p", chan);
>>>>> +
>>>>> +	hci_conn_hold(conn->hcon);
>>>>
>>>> Holding the hcon will keep the ACL open after all of the other L2CAP
>>>> channels have closed (unless I missed some code later in the patch
>>>> series).  The A2MP fixed channel should not keep the ACL open.  If
>>>> the connection is not held here, then there shouldn't be a put in
>>>> l2cap_chan_del for the A2MP channel either.
>>>
>>> l2cap_chan_del makes hci_conn_put, also for a2mp channel. The behavior is
>>> the same for fixed and normal channels.
>>
>> And when does l2cap_chan_del get called for a fixed channel?  The
>> fixed channel must not do an hci_conn_hold so the ACL is allowed to
>> close when all dynamic L2CAP channels have closed.
>
> The current approach is to have amp_mgr for hci_conn. It will be freed
> when in hci_conn_del together with other l2cap channels in
> hci_chan_list_flush and then we make amp_mgr_put() and destroy mgr.
>
> The idea is to make a2mp chan similar to other chans and other chans do
> hci_conn_hold and hci_conn_put. Otherwise I would need to add extra checks
> before hci_conn_put which is ugly.
>
> I've tested this with PTS and no memory leaks found so far.

The risk is not memory leaks - if the other device closes the ACL, 
then the A2MP channel will be cleaned up.  But if you had two BlueZ 
devices with A2MP connected to each other, the ACL would never close 
as long as the devices remained powered and in range!  Nothing would 
trigger the flush as long as the hci_conn is held.

I think the checks for hci_conn_put are necessary, even if they are 
ugly.

--
Mat Martineau
Employee of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum


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

* Re: [PATCHv1 01/17] Bluetooth: A2MP: Create A2MP channel
  2012-05-24 15:59           ` Mat Martineau
@ 2012-05-25  8:09             ` Andrei Emeltchenko
  2012-05-25 17:18               ` Mat Martineau
  0 siblings, 1 reply; 104+ messages in thread
From: Andrei Emeltchenko @ 2012-05-25  8:09 UTC (permalink / raw)
  To: Mat Martineau; +Cc: linux-bluetooth, pkrystad

Hi Mat,

On Thu, May 24, 2012 at 08:59:57AM -0700, Mat Martineau wrote:
> On Thu, 24 May 2012, Andrei Emeltchenko wrote:
> >On Wed, May 23, 2012 at 08:44:22AM -0700, Mat Martineau wrote:
> >>>>>+static struct l2cap_chan *a2mp_chan_open(struct l2cap_conn *conn)
> >>>>>+{
> >>>>>+	struct l2cap_chan *chan;
> >>>>>+
> >>>>>+	chan = l2cap_chan_create();
> >>>>>+	if (!chan)
> >>>>>+		return NULL;
> >>>>>+
> >>>>>+	BT_DBG("chan %p", chan);
> >>>>>+
> >>>>>+	hci_conn_hold(conn->hcon);
> >>>>
> >>>>Holding the hcon will keep the ACL open after all of the other L2CAP
> >>>>channels have closed (unless I missed some code later in the patch
> >>>>series).  The A2MP fixed channel should not keep the ACL open.  If
> >>>>the connection is not held here, then there shouldn't be a put in
> >>>>l2cap_chan_del for the A2MP channel either.
> >>>
> >>>l2cap_chan_del makes hci_conn_put, also for a2mp channel. The behavior is
> >>>the same for fixed and normal channels.
> >>
> >>And when does l2cap_chan_del get called for a fixed channel?  The
> >>fixed channel must not do an hci_conn_hold so the ACL is allowed to
> >>close when all dynamic L2CAP channels have closed.
> >
> >The current approach is to have amp_mgr for hci_conn. It will be freed
> >when in hci_conn_del together with other l2cap channels in
> >hci_chan_list_flush and then we make amp_mgr_put() and destroy mgr.
> >
> >The idea is to make a2mp chan similar to other chans and other chans do
> >hci_conn_hold and hci_conn_put. Otherwise I would need to add extra checks
> >before hci_conn_put which is ugly.
> >
> >I've tested this with PTS and no memory leaks found so far.
> 
> The risk is not memory leaks - if the other device closes the ACL,
> then the A2MP channel will be cleaned up.  But if you had two BlueZ
> devices with A2MP connected to each other, the ACL would never close
> as long as the devices remained powered and in range!  Nothing would
> trigger the flush as long as the hci_conn is held.

Does it indicate that we have problem with rather freeing amp_mgr?

> I think the checks for hci_conn_put are necessary, even if they are
> ugly.

I think that if I have hci_conn_hold when creating channel and
hci_conn_put when closing channel that does not differ from the case when
I do not have hci_conn_put/hold.

So you are probably referring to the case when hci_conn needs to be closed
but cannot because it has hci_conn_hold in a2mp channel? This also means
that we still have L2CAP channel (a2mp) hanging. This seems right to me if
I did not miss something.

Best regards 
Andrei Emeltchenko 


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

* Re: [PATCHv3 10/18] Bluetooth: A2MP: Process A2MP Discover Request
  2012-05-24 11:38   ` [PATCHv3 10/18] Bluetooth: A2MP: Process A2MP Discover Request Andrei Emeltchenko
@ 2012-05-25 12:19     ` Gustavo Padovan
  2012-05-25 13:11       ` Andrei Emeltchenko
  0 siblings, 1 reply; 104+ messages in thread
From: Gustavo Padovan @ 2012-05-25 12:19 UTC (permalink / raw)
  To: Andrei Emeltchenko; +Cc: linux-bluetooth

Hi Andrei,

* Andrei Emeltchenko <Andrei.Emeltchenko.news@gmail.com> [2012-05-24 14:38:20 +0300]:

> From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
> 
> Adds helper functions to count HCI devs and process A2MP Discover
> Request, code makes sure that first controller in the list is
> BREDR one. Trace is shown below:
> 
> ...
> > ACL data: handle 11 flags 0x02 dlen 16
>     A2MP: Discover req: mtu/mps 670 mask: 0x0000
> < ACL data: handle 11 flags 0x00 dlen 22
>     A2MP: Discover rsp: mtu/mps 670 mask: 0x0000
>       Controller list:
>         id 0 type 0 (BR-EDR) status 0x01 (Bluetooth only)
>         id 1 type 1 (802.11 AMP) status 0x01 (Bluetooth only)
> ...
> 
> Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
> ---
>  include/net/bluetooth/a2mp.h     |    2 +
>  include/net/bluetooth/hci.h      |    3 ++
>  include/net/bluetooth/hci_core.h |   13 ++++++
>  net/bluetooth/a2mp.c             |   85 ++++++++++++++++++++++++++++++++++++++
>  4 files changed, 103 insertions(+)
> 
> diff --git a/include/net/bluetooth/a2mp.h b/include/net/bluetooth/a2mp.h
> index 391acd7..96f9cc2 100644
> --- a/include/net/bluetooth/a2mp.h
> +++ b/include/net/bluetooth/a2mp.h
> @@ -15,6 +15,8 @@
>  #ifndef __A2MP_H
>  #define __A2MP_H
>  
> +#define A2MP_FEAT_EXT	0x8000
> +
>  struct amp_mgr {
>  	struct l2cap_conn	*l2cap_conn;
>  	struct l2cap_chan	*a2mp_chan;
> diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
> index edb6639..158f403 100644
> --- a/include/net/bluetooth/hci.h
> +++ b/include/net/bluetooth/hci.h
> @@ -58,6 +58,9 @@
>  #define HCI_BREDR	0x00
>  #define HCI_AMP		0x01
>  
> +/* First BR/EDR Controller shall have ID = 0 */
> +#define HCI_BREDR_ID	0
> +
>  /* HCI device quirks */
>  enum {
>  	HCI_QUIRK_RESET_ON_CLOSE,
> diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
> index 6e64b76..20fd573 100644
> --- a/include/net/bluetooth/hci_core.h
> +++ b/include/net/bluetooth/hci_core.h
> @@ -641,6 +641,19 @@ static inline void hci_set_drvdata(struct hci_dev *hdev, void *data)
>  	dev_set_drvdata(&hdev->dev, data);
>  }
>  
> +/* hci_dev_list shall be locked */
> +static inline uint8_t __hci_num_ctrl(void)
> +{
> +	uint8_t count = 0;
> +	struct list_head *p;
> +
> +	list_for_each(p, &hci_dev_list) {
> +		count++;
> +	}
> +
> +	return count;
> +}
> +
>  struct hci_dev *hci_dev_get(int index);
>  struct hci_dev *hci_get_route(bdaddr_t *src, bdaddr_t *dst);
>  
> diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c
> index 4137f9b..ac095ac 100644
> --- a/net/bluetooth/a2mp.c
> +++ b/net/bluetooth/a2mp.c
> @@ -63,6 +63,36 @@ static void a2mp_send(struct amp_mgr *mgr, u8 code, u8 ident, u16 len,
>  	kfree(cmd);
>  }
>  
> +static inline void __a2mp_cl_bredr(struct a2mp_cl *cl)
> +{
> +	cl->id = 0;
> +	cl->type = 0;
> +	cl->status = 1;
> +}
> +
> +/* hci_dev_list shall be locked */
> +static void __a2mp_add_cl(struct amp_mgr *mgr, struct a2mp_cl *cl, u8 num_ctrl)
> +{
> +	int i = 0;
> +	struct hci_dev *hdev;
> +
> +	__a2mp_cl_bredr(cl);
> +
> +	list_for_each_entry(hdev, &hci_dev_list, list) {
> +		/* Iterate through AMP controllers */
> +		if (hdev->id == HCI_BREDR_ID)
> +			continue;
> +
> +		/* Starting from second entry */
> +		if (++i >= num_ctrl)
> +			return;
> +
> +		cl[i].id = hdev->id;
> +		cl[i].type = hdev->amp_type;
> +		cl[i].status = hdev->amp_status;
> +	}
> +}
> +
>  /* Processing A2MP messages */
>  static int a2mp_command_rej(struct amp_mgr *mgr, struct sk_buff *skb,
>  			    struct a2mp_cmd *hdr)
> @@ -79,6 +109,58 @@ static int a2mp_command_rej(struct amp_mgr *mgr, struct sk_buff *skb,
>  	return 0;
>  }
>  
> +static int a2mp_discover_req(struct amp_mgr *mgr, struct sk_buff *skb,
> +			     struct a2mp_cmd *hdr)
> +{
> +	struct a2mp_discov_req *req = (struct a2mp_discov_req *) skb->data;

Just use (void *) as cast here.

> +	u16 len = le16_to_cpu(hdr->len);
> +	struct a2mp_discov_rsp *rsp;
> +	u16 ext_feat;
> +	u8 num_ctrl;
> +
> +	if (len < sizeof(*req))
> +		return -EINVAL;
> +
> +	skb_pull(skb, sizeof(*req));
> +
> +	ext_feat = le16_to_cpu(req->ext_feat);
> +
> +	BT_DBG("mtu %d efm 0x%4.4x", le16_to_cpu(req->mtu), ext_feat);
> +
> +	/* check that packet is not broken for now */
> +	while (ext_feat & A2MP_FEAT_EXT) {
> +		if (len < sizeof(ext_feat))
> +			return -EINVAL;
> +
> +		ext_feat = get_unaligned_le16(skb->data);
> +		BT_DBG("efm 0x%4.4x", ext_feat);
> +		len -= sizeof(ext_feat);
> +		skb_pull(skb, sizeof(ext_feat));
> +	}
> +
> +	read_lock(&hci_dev_list_lock);
> +
> +	num_ctrl = __hci_num_ctrl();
> +	len = num_ctrl * sizeof(struct a2mp_cl) + sizeof(*rsp);
> +	rsp = kmalloc(len, GFP_ATOMIC);
> +	if (!rsp) {
> +		read_unlock(&hci_dev_list_lock);
> +		return -ENOMEM;
> +	}
> +
> +	rsp->mtu = cpu_to_le16(L2CAP_A2MP_DEFAULT_MTU);

__constant_cpu_to_le16() here.

> +	rsp->ext_feat = 0;
> +
> +	__a2mp_add_cl(mgr, rsp->cl, num_ctrl);
> +
> +	read_unlock(&hci_dev_list_lock);
> +
> +	a2mp_send(mgr, A2MP_DISCOVER_RSP, hdr->ident, len, rsp);
> +
> +	kfree(rsp);
> +	return 0;
> +}
> +
>  /* Handle A2MP signalling */
>  static int a2mp_chan_recv_cb(void *data, struct sk_buff *skb)
>  {
> @@ -109,6 +191,9 @@ static int a2mp_chan_recv_cb(void *data, struct sk_buff *skb)
>  			break;
>  
>  		case A2MP_DISCOVER_REQ:
> +			err = a2mp_discover_req(mgr, skb, hdr);
> +			break;
> +
>  		case A2MP_CHANGE_NOTIFY:
>  		case A2MP_GETINFO_REQ:
>  		case A2MP_GETAMPASSOC_REQ:
> -- 
> 1.7.9.5
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

	Gustavo

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

* Re: [PATCHv3 05/18] Bluetooth: A2MP: Add chan callbacks
  2012-05-24 11:38   ` [PATCHv3 05/18] Bluetooth: A2MP: Add chan callbacks Andrei Emeltchenko
@ 2012-05-25 12:20     ` Gustavo Padovan
  2012-05-25 13:08       ` Andrei Emeltchenko
  0 siblings, 1 reply; 104+ messages in thread
From: Gustavo Padovan @ 2012-05-25 12:20 UTC (permalink / raw)
  To: Andrei Emeltchenko; +Cc: linux-bluetooth

Hi Andrei,

* Andrei Emeltchenko <Andrei.Emeltchenko.news@gmail.com> [2012-05-24 14:38:15 +0300]:

> From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
> 
> Add state change, close and skb allocation callbacks.
> 
> Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
> ---
>  net/bluetooth/a2mp.c |   40 ++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 40 insertions(+)
> 
> diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c
> index e7e5f5f..eb98541 100644
> --- a/net/bluetooth/a2mp.c
> +++ b/net/bluetooth/a2mp.c
> @@ -63,8 +63,46 @@ static void a2mp_send(struct amp_mgr *mgr, u8 code, u8 ident, u16 len,
>  	kfree(cmd);
>  }
>  
> +static void a2mp_chan_state_change_cb(void *data, int state)
> +{
> +	struct amp_mgr *mgr = data;
> +	struct l2cap_chan *chan;
> +
> +	if (!mgr)
> +		return;
> +
> +	chan = mgr->a2mp_chan;
> +
> +	BT_DBG("chan %p state %s", chan, state_to_string(state));
> +
> +	chan->state = state;
> +
> +	switch (state) {
> +	case BT_CLOSED:
> +		if (mgr)
> +			amp_mgr_put(mgr);
> +		break;
> +	}
> +}
> +
> +static void a2mp_chan_close_cb(void *data)
> +{
> +	struct amp_mgr *mgr = data;
> +
> +	l2cap_chan_destroy(mgr->a2mp_chan);
> +}
> +
> +static struct sk_buff *a2mp_chan_alloc_skb_cb(struct l2cap_chan *chan,
> +					      unsigned long len, int nb)
> +{
> +	return bt_skb_alloc(len, GFP_KERNEL);
> +}
> +
>  static struct l2cap_ops a2mp_chan_ops = {
>  	.name = "L2CAP A2MP channel",
> +	.state_change = a2mp_chan_state_change_cb,
> +	.close = a2mp_chan_close_cb,
> +	.alloc_skb = a2mp_chan_alloc_skb_cb,
>  };
>  
>  static struct l2cap_chan *a2mp_chan_open(struct l2cap_conn *conn)
> @@ -110,6 +148,8 @@ static struct l2cap_chan *a2mp_chan_open(struct l2cap_conn *conn)
>  	chan->remote_mps = chan->omtu;
>  	chan->mps = chan->omtu;
>  
> +	chan->state = BT_CONNECTED;
> +

This change seems to be unrelated to this patch.

	Gustavo

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

* Re: [PATCHv3 11/18] Bluetooth: A2MP: Process A2MP Change Notify
  2012-05-24 11:38   ` [PATCHv3 11/18] Bluetooth: A2MP: Process A2MP Change Notify Andrei Emeltchenko
@ 2012-05-25 12:29     ` Gustavo Padovan
  0 siblings, 0 replies; 104+ messages in thread
From: Gustavo Padovan @ 2012-05-25 12:29 UTC (permalink / raw)
  To: Andrei Emeltchenko; +Cc: linux-bluetooth

Hi Andrei,

* Andrei Emeltchenko <Andrei.Emeltchenko.news@gmail.com> [2012-05-24 14:38:21 +0300]:

> From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
> 
> Placeholder for A2MP Change Notify handler.
> 
> Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
> ---
>  net/bluetooth/a2mp.c |   19 +++++++++++++++++++
>  1 file changed, 19 insertions(+)
> 
> diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c
> index ac095ac..d60be75 100644
> --- a/net/bluetooth/a2mp.c
> +++ b/net/bluetooth/a2mp.c
> @@ -161,6 +161,22 @@ static int a2mp_discover_req(struct amp_mgr *mgr, struct sk_buff *skb,
>  	return 0;
>  }
>  
> +static int a2mp_change_notify(struct amp_mgr *mgr, struct sk_buff *skb,
> +			      struct a2mp_cmd *hdr)
> +{
> +	struct a2mp_cl *cl = (struct a2mp_cl *) skb->data;

Use void *. Same for the next patches in this series.

	Gustavo

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

* Re: [PATCHv3 05/18] Bluetooth: A2MP: Add chan callbacks
  2012-05-25 12:20     ` Gustavo Padovan
@ 2012-05-25 13:08       ` Andrei Emeltchenko
  0 siblings, 0 replies; 104+ messages in thread
From: Andrei Emeltchenko @ 2012-05-25 13:08 UTC (permalink / raw)
  To: Gustavo Padovan, linux-bluetooth

Hi Gustavo,

On Fri, May 25, 2012 at 09:20:37AM -0300, Gustavo Padovan wrote:
> >  static struct l2cap_chan *a2mp_chan_open(struct l2cap_conn *conn)
> > @@ -110,6 +148,8 @@ static struct l2cap_chan *a2mp_chan_open(struct l2cap_conn *conn)
> >  	chan->remote_mps = chan->omtu;
> >  	chan->mps = chan->omtu;
> >  
> > +	chan->state = BT_CONNECTED;
> > +
> 
> This change seems to be unrelated to this patch.

OK, I move it to the first patch.

Best regards 
Andrei Emeltchenko 

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

* Re: [PATCHv3 10/18] Bluetooth: A2MP: Process A2MP Discover Request
  2012-05-25 12:19     ` Gustavo Padovan
@ 2012-05-25 13:11       ` Andrei Emeltchenko
  0 siblings, 0 replies; 104+ messages in thread
From: Andrei Emeltchenko @ 2012-05-25 13:11 UTC (permalink / raw)
  To: Gustavo Padovan, linux-bluetooth

Hi Gustavo,

On Fri, May 25, 2012 at 09:19:34AM -0300, Gustavo Padovan wrote:
> Hi Andrei,
> 
> > +static int a2mp_discover_req(struct amp_mgr *mgr, struct sk_buff *skb,
> > +			     struct a2mp_cmd *hdr)
> > +{
> > +	struct a2mp_discov_req *req = (struct a2mp_discov_req *) skb->data;
> 
> Just use (void *) as cast here.

This actually does not matter but I can change it. This is pity that it
was not mentioned in the 20 previous reviews ;(

> > +	rsp->mtu = cpu_to_le16(L2CAP_A2MP_DEFAULT_MTU);
> 
> __constant_cpu_to_le16() here.

OK.

Best regards 
Andrei Emeltchenko 

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

* Re: [PATCHv1 01/17] Bluetooth: A2MP: Create A2MP channel
  2012-05-25  8:09             ` Andrei Emeltchenko
@ 2012-05-25 17:18               ` Mat Martineau
  2012-05-28  7:24                 ` Andrei Emeltchenko
  0 siblings, 1 reply; 104+ messages in thread
From: Mat Martineau @ 2012-05-25 17:18 UTC (permalink / raw)
  To: Andrei Emeltchenko; +Cc: linux-bluetooth, pkrystad, marcel


Andrei -

On Fri, 25 May 2012, Andrei Emeltchenko wrote:

> Hi Mat,
>
> On Thu, May 24, 2012 at 08:59:57AM -0700, Mat Martineau wrote:
>> On Thu, 24 May 2012, Andrei Emeltchenko wrote:
>>> On Wed, May 23, 2012 at 08:44:22AM -0700, Mat Martineau wrote:
>>>>>>> +static struct l2cap_chan *a2mp_chan_open(struct l2cap_conn *conn)
>>>>>>> +{
>>>>>>> +	struct l2cap_chan *chan;
>>>>>>> +
>>>>>>> +	chan = l2cap_chan_create();
>>>>>>> +	if (!chan)
>>>>>>> +		return NULL;
>>>>>>> +
>>>>>>> +	BT_DBG("chan %p", chan);
>>>>>>> +
>>>>>>> +	hci_conn_hold(conn->hcon);
>>>>>>
>>>>>> Holding the hcon will keep the ACL open after all of the other L2CAP
>>>>>> channels have closed (unless I missed some code later in the patch
>>>>>> series).  The A2MP fixed channel should not keep the ACL open.  If
>>>>>> the connection is not held here, then there shouldn't be a put in
>>>>>> l2cap_chan_del for the A2MP channel either.
>>>>>
>>>>> l2cap_chan_del makes hci_conn_put, also for a2mp channel. The behavior is
>>>>> the same for fixed and normal channels.
>>>>
>>>> And when does l2cap_chan_del get called for a fixed channel?  The
>>>> fixed channel must not do an hci_conn_hold so the ACL is allowed to
>>>> close when all dynamic L2CAP channels have closed.
>>>
>>> The current approach is to have amp_mgr for hci_conn. It will be freed
>>> when in hci_conn_del together with other l2cap channels in
>>> hci_chan_list_flush and then we make amp_mgr_put() and destroy mgr.
>>>
>>> The idea is to make a2mp chan similar to other chans and other chans do
>>> hci_conn_hold and hci_conn_put. Otherwise I would need to add extra checks
>>> before hci_conn_put which is ugly.
>>>
>>> I've tested this with PTS and no memory leaks found so far.
>>
>> The risk is not memory leaks - if the other device closes the ACL,
>> then the A2MP channel will be cleaned up.  But if you had two BlueZ
>> devices with A2MP connected to each other, the ACL would never close
>> as long as the devices remained powered and in range!  Nothing would
>> trigger the flush as long as the hci_conn is held.
>
> Does it indicate that we have problem with rather freeing amp_mgr?

It looks like the amp_mgr will be freed if the channel is closed. 
There's nothing that will close the channel except for:

* Remote device disconnects the ACL
* Remote device goes out of range
* Local BR/EDR controller is powered down or reset

>> I think the checks for hci_conn_put are necessary, even if they are
>> ugly.
>
> I think that if I have hci_conn_hold when creating channel and
> hci_conn_put when closing channel that does not differ from the case when
> I do not have hci_conn_put/hold.

If there was something that closed the A2MP channel, there would be no 
difference.  But nothing closes the A2MP channel.

> So you are probably referring to the case when hci_conn needs to be closed
> but cannot because it has hci_conn_hold in a2mp channel?

Yes.

> This also means that we still have L2CAP channel (a2mp) hanging.
> This seems right to me if I did not miss something.

Since A2MP is a fixed channel, it is not opened and closed like 
typical L2CAP channels.  Consider this scenario:

1. Remote device decides to connect
2. ACL is created
3. Remote device sends A2MP discover
4. A2MP channel is set up, AMP manager is created, hci_conn_hold for 
A2MP channel
5. Remote device connects L2CAP channel over BR/EDR.  hci_conn_hold 
for the data channel
6. A2MP communication to set up physical link
7. L2CAP channel move to AMP controller
8. Data sent over AMP.
9. L2CAP channel disconnected, hci_conn_put for the data channel
10. Device stays in range.  hci_conn reference count is not 0, so ACL 
is not closed.

If you reach step 10 and both sides are BlueZ, the ACL stays active 
and BT is using extra power.

If you did not do the hci_conn_hold in step 4, the ACL would be 
disconnected 2 seconds after step 9, allowing the BR/EDR baseband to 
go in to a low power state.

--
Mat Martineau
Employee of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum

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

* Re: [PATCHv1 01/17] Bluetooth: A2MP: Create A2MP channel
  2012-05-25 17:18               ` Mat Martineau
@ 2012-05-28  7:24                 ` Andrei Emeltchenko
  2012-05-28 13:59                   ` Andrei Emeltchenko
  0 siblings, 1 reply; 104+ messages in thread
From: Andrei Emeltchenko @ 2012-05-28  7:24 UTC (permalink / raw)
  To: Mat Martineau; +Cc: linux-bluetooth, pkrystad, marcel

Hi Mat,

On Fri, May 25, 2012 at 10:18:20AM -0700, Mat Martineau wrote:
> >On Thu, May 24, 2012 at 08:59:57AM -0700, Mat Martineau wrote:
> >>On Thu, 24 May 2012, Andrei Emeltchenko wrote:
> >>>On Wed, May 23, 2012 at 08:44:22AM -0700, Mat Martineau wrote:
> >>>>>>>+static struct l2cap_chan *a2mp_chan_open(struct l2cap_conn *conn)
> >>>>>>>+{
> >>>>>>>+	struct l2cap_chan *chan;
> >>>>>>>+
> >>>>>>>+	chan = l2cap_chan_create();
> >>>>>>>+	if (!chan)
> >>>>>>>+		return NULL;
> >>>>>>>+
> >>>>>>>+	BT_DBG("chan %p", chan);
> >>>>>>>+
> >>>>>>>+	hci_conn_hold(conn->hcon);
> >>>>>>
> >>>>>>Holding the hcon will keep the ACL open after all of the other L2CAP
> >>>>>>channels have closed (unless I missed some code later in the patch
> >>>>>>series).  The A2MP fixed channel should not keep the ACL open.  If
> >>>>>>the connection is not held here, then there shouldn't be a put in
> >>>>>>l2cap_chan_del for the A2MP channel either.
> >>>>>
> >>>>>l2cap_chan_del makes hci_conn_put, also for a2mp channel. The behavior is
> >>>>>the same for fixed and normal channels.
> >>>>
> >>>>And when does l2cap_chan_del get called for a fixed channel?  The
> >>>>fixed channel must not do an hci_conn_hold so the ACL is allowed to
> >>>>close when all dynamic L2CAP channels have closed.
> >>>
> >>>The current approach is to have amp_mgr for hci_conn. It will be freed
> >>>when in hci_conn_del together with other l2cap channels in
> >>>hci_chan_list_flush and then we make amp_mgr_put() and destroy mgr.
> >>>
> >>>The idea is to make a2mp chan similar to other chans and other chans do
> >>>hci_conn_hold and hci_conn_put. Otherwise I would need to add extra checks
> >>>before hci_conn_put which is ugly.
> >>>
> >>>I've tested this with PTS and no memory leaks found so far.
> >>
> >>The risk is not memory leaks - if the other device closes the ACL,
> >>then the A2MP channel will be cleaned up.  But if you had two BlueZ
> >>devices with A2MP connected to each other, the ACL would never close
> >>as long as the devices remained powered and in range!  Nothing would
> >>trigger the flush as long as the hci_conn is held.
> >
> >Does it indicate that we have problem with rather freeing amp_mgr?
> 
> It looks like the amp_mgr will be freed if the channel is closed.
> There's nothing that will close the channel except for:
> 
> * Remote device disconnects the ACL
> * Remote device goes out of range
> * Local BR/EDR controller is powered down or reset
> 
> >>I think the checks for hci_conn_put are necessary, even if they are
> >>ugly.
> >
> >I think that if I have hci_conn_hold when creating channel and
> >hci_conn_put when closing channel that does not differ from the case when
> >I do not have hci_conn_put/hold.
> 
> If there was something that closed the A2MP channel, there would be
> no difference.  But nothing closes the A2MP channel.

I actually was thinking about timers which could do clean up.

> >So you are probably referring to the case when hci_conn needs to be closed
> >but cannot because it has hci_conn_hold in a2mp channel?
> 
> Yes.
> 
> >This also means that we still have L2CAP channel (a2mp) hanging.
> >This seems right to me if I did not miss something.
> 
> Since A2MP is a fixed channel, it is not opened and closed like
> typical L2CAP channels.  Consider this scenario:
> 
> 1. Remote device decides to connect
> 2. ACL is created
> 3. Remote device sends A2MP discover
> 4. A2MP channel is set up, AMP manager is created, hci_conn_hold for
> A2MP channel
> 5. Remote device connects L2CAP channel over BR/EDR.  hci_conn_hold
> for the data channel
> 6. A2MP communication to set up physical link
> 7. L2CAP channel move to AMP controller
> 8. Data sent over AMP.
> 9. L2CAP channel disconnected, hci_conn_put for the data channel
> 10. Device stays in range.  hci_conn reference count is not 0, so
> ACL is not closed.

My concern here if A2MP does not reference hci_conn can hci_conn be
removed while we still have A2MP chan in some situation?

I will modify code that A2MP does not reference hci_conn, or create
special patch with this change.

Best regards 
Andrei Emeltchenko 


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

* Re: [PATCHv1 01/17] Bluetooth: A2MP: Create A2MP channel
  2012-05-28  7:24                 ` Andrei Emeltchenko
@ 2012-05-28 13:59                   ` Andrei Emeltchenko
  2012-05-29 16:23                     ` Mat Martineau
  0 siblings, 1 reply; 104+ messages in thread
From: Andrei Emeltchenko @ 2012-05-28 13:59 UTC (permalink / raw)
  To: Mat Martineau, linux-bluetooth, pkrystad, marcel

Hi Mat,

On Mon, May 28, 2012 at 10:24:56AM +0300, Andrei Emeltchenko wrote:
> > >>The risk is not memory leaks - if the other device closes the ACL,
> > >>then the A2MP channel will be cleaned up.  But if you had two BlueZ
> > >>devices with A2MP connected to each other, the ACL would never close
> > >>as long as the devices remained powered and in range!  Nothing would
> > >>trigger the flush as long as the hci_conn is held.
> > >
> > >Does it indicate that we have problem with rather freeing amp_mgr?
> > 
> > It looks like the amp_mgr will be freed if the channel is closed.
> > There's nothing that will close the channel except for:
> > 
> > * Remote device disconnects the ACL
> > * Remote device goes out of range
> > * Local BR/EDR controller is powered down or reset
> > 
> > >>I think the checks for hci_conn_put are necessary, even if they are
> > >>ugly.
> > >
> > >I think that if I have hci_conn_hold when creating channel and
> > >hci_conn_put when closing channel that does not differ from the case when
> > >I do not have hci_conn_put/hold.
> > 
> > If there was something that closed the A2MP channel, there would be
> > no difference.  But nothing closes the A2MP channel.
> 
> I actually was thinking about timers which could do clean up.
> 
> > >So you are probably referring to the case when hci_conn needs to be closed
> > >but cannot because it has hci_conn_hold in a2mp channel?
> > 
> > Yes.
> > 
> > >This also means that we still have L2CAP channel (a2mp) hanging.
> > >This seems right to me if I did not miss something.
> > 
> > Since A2MP is a fixed channel, it is not opened and closed like
> > typical L2CAP channels.  Consider this scenario:
> > 
> > 1. Remote device decides to connect
> > 2. ACL is created
> > 3. Remote device sends A2MP discover
> > 4. A2MP channel is set up, AMP manager is created, hci_conn_hold for
> > A2MP channel
> > 5. Remote device connects L2CAP channel over BR/EDR.  hci_conn_hold
> > for the data channel
> > 6. A2MP communication to set up physical link
> > 7. L2CAP channel move to AMP controller
> > 8. Data sent over AMP.
> > 9. L2CAP channel disconnected, hci_conn_put for the data channel
> > 10. Device stays in range.  hci_conn reference count is not 0, so
> > ACL is not closed.
> 
> My concern here if A2MP does not reference hci_conn can hci_conn be
> removed while we still have A2MP chan in some situation?

I just tested code with PTS and got one crash:

<------8<--------------------------------------------------------------------
|  [  275.100760] [5] hci_chan_del: hci0 conn f3ff0800 chan e818e540
|  [  275.109610] [19] l2cap_send_rr_or_rnr: chan e806b800, poll 0
|  [  275.127922] [19] l2cap_send_sframe: chan e806b800, control f5ef3ed8
|  [  275.133532] [19] l2cap_send_sframe: reqseq 2, final 0, poll 0, super 0
|  [  275.173033] [5] hci_conn_del: hci0 conn f3ff0800 handle 11
|  [  275.181131] [5] hci_chan_list_flush: conn f3ff0800
|  [  275.202645] [5] amp_mgr_put: mgr e8260600
<------8<--------------------------------------------------------------------

Here we deleted the last L2CAP channel

<------8<------------------------------------------------------------------
|  [  275.295020] BUG: unable to handle kernel NULL pointer dereference at
|  (null)
|  [  275.298791] IP: [<f8362e6c>] l2cap_do_send+0x1c/0xa0 [bluetooth]
|  [  275.298791] *pde = 00000000
|  [  275.298791] Oops: 0000 [#1] SMP
<------8<------------------------------------------------------------------

Then we got the crash probably hci_conn deleted faster then we get reply
from AMP controller

<------8<---------------------------------------------------------------------
|  [  275.298791] EIP: [<f8362e6c>] l2cap_do_send+0x1c/0xa0 [bluetooth]
|  SS:ESP 0068:f5ef3e58
|  [  275.298791] CR2: 0000000000000000
|  [  276.553113] Bluetooth: hci1 command tx timeout
|  [  276.553706] ---[ end trace b08f23ddb2b49a2e ]---
|  [  276.577494] [30] hci_queue_cb: Queue cmd ed3d5540 opt e8260600
|  [  276.723885] [30] l2cap_segment_sdu: chan e806b800, msg f5919e94, len 22
|  [  276.790990] BUG: unable to handle kernel NULL pointer dereference at
|  00000010
|  [  276.794865] IP: [<f83694dd>] l2cap_chan_send+0x28d/0xb40 [bluetooth]
<------8<---------------------------------------------------------------------

Best regards 
Andrei Emeltchenko 

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

* [PATCHv4 00/17] Bluetooth A2MP implementation
  2012-05-18 14:25 [PATCHv1 00/17] Bluetooth A2MP implementation Andrei Emeltchenko
                   ` (19 preceding siblings ...)
  2012-05-24 11:38 ` [PATCHv3 00/18] Bluetooth A2MP implementation Andrei Emeltchenko
@ 2012-05-29 10:59 ` Andrei Emeltchenko
  2012-05-29 10:59   ` [PATCHv4 01/17] Bluetooth: A2MP: Create A2MP channel Andrei Emeltchenko
                     ` (16 more replies)
  20 siblings, 17 replies; 104+ messages in thread
From: Andrei Emeltchenko @ 2012-05-29 10:59 UTC (permalink / raw)
  To: linux-bluetooth

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

Basic A2MP implementation.

Changes:
	* PATCHv4: Rebased against recent tree, changed type conversion to (void *),
	added dummy "no_function"s in a2mp chan ops.
	* PATCHv3: Skipped unlink callback since Gustavo seems to have better
	approach, added NULL pointer checks reported by Mat.
	* PATCHv2: Rebased against recent changes, changed amp_mgr list to pointer
	in hci_conn, reworked handling fixed channels and create A2MP channel patches,
	adding unlink and ready callbacks to get rid of socket dependecies in L2CAP and
	other minor fixes.
	* PATCHv1: Rebasing against latest tree and minor fixes.
	* RFCv7: Taking comments from review in linux-bluetooth.
	* RFCv6: Remove some unneded check for sk since they are in different path
	(A2MP decoded as a data channel wrt L2CAP signalling channel). Style fixes.
	* RFCv5: Fix memory leaks, sparse warnings and taking comments from upstream.
	* RFCv4: redesign code to use l2cap channel lock instead of socket lock
	and general modifications. Basic implementation of HCI callback interface.
	* RFCv3: redesign code to use l2cap functions instead of kernel sockets
	L2CAP functions modified to work with channels without sk.
	* RFCv2: rebased against "workqueue" patches.
	* RFCv1: added refcnt to amp_mgr, fixed sleeping in atomic

Initially code was based of reference implementations below:

References: Code Aurora (git://codeaurora.org/kernel/msm.git) and Atheros
(search for: [PATCH 2/3] Add a2mp protocol/AMP manager, by Atheros Linux BT3)
implementations.

Andrei Emeltchenko (17):
  Bluetooth: A2MP: Create A2MP channel
  Bluetooth: A2MP: AMP Manager basic functions
  Bluetooth: A2MP: Build and Send msg helpers
  Bluetooth: A2MP: Add chan callbacks
  Bluetooth: A2MP: Definitions for A2MP commands
  Bluetooth: A2MP: Define A2MP status codes
  Bluetooth: A2MP: Process A2MP messages
  Bluetooth: A2MP: Process A2MP Command Reject
  Bluetooth: A2MP: Process A2MP Discover Request
  Bluetooth: A2MP: Process A2MP Change Notify
  Bluetooth: A2MP: Process A2MP Get Info Request
  Bluetooth: A2MP: Process A2MP Get AMP Assoc Request
  Bluetooth: A2MP: Process A2MP Create Physlink Request
  Bluetooth: A2MP: Process A2MP Disc Physlink Request
  Bluetooth: A2MP: Process A2MP Command Responses
  Bluetooth: A2MP: Handling fixed channels
  Bluetooth: A2MP: Manage incoming connections

 include/net/bluetooth/a2mp.h     |  126 ++++++++
 include/net/bluetooth/hci.h      |    3 +
 include/net/bluetooth/hci_core.h |   14 +
 include/net/bluetooth/l2cap.h    |    7 +
 net/bluetooth/Makefile           |    3 +-
 net/bluetooth/a2mp.c             |  589 ++++++++++++++++++++++++++++++++++++++
 net/bluetooth/hci_conn.c         |    4 +
 net/bluetooth/l2cap_core.c       |   42 ++-
 8 files changed, 780 insertions(+), 8 deletions(-)
 create mode 100644 include/net/bluetooth/a2mp.h
 create mode 100644 net/bluetooth/a2mp.c

-- 
1.7.9.5


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

* [PATCHv4 01/17] Bluetooth: A2MP: Create A2MP channel
  2012-05-29 10:59 ` [PATCHv4 00/17] Bluetooth A2MP implementation Andrei Emeltchenko
@ 2012-05-29 10:59   ` Andrei Emeltchenko
  2012-05-29 10:59   ` [PATCHv4 02/17] Bluetooth: A2MP: AMP Manager basic functions Andrei Emeltchenko
                     ` (15 subsequent siblings)
  16 siblings, 0 replies; 104+ messages in thread
From: Andrei Emeltchenko @ 2012-05-29 10:59 UTC (permalink / raw)
  To: linux-bluetooth

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

Create and initialize fixed A2MP channel

Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
 include/net/bluetooth/l2cap.h |    6 ++++
 net/bluetooth/Makefile        |    3 +-
 net/bluetooth/a2mp.c          |   69 +++++++++++++++++++++++++++++++++++++++++
 net/bluetooth/l2cap_core.c    |    6 ++--
 4 files changed, 80 insertions(+), 4 deletions(-)
 create mode 100644 net/bluetooth/a2mp.c

diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index c5726c2..aaba222 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -52,6 +52,8 @@
 #define L2CAP_CONN_TIMEOUT		msecs_to_jiffies(40000)
 #define L2CAP_INFO_TIMEOUT		msecs_to_jiffies(4000)
 
+#define L2CAP_A2MP_DEFAULT_MTU		670
+
 /* L2CAP socket address */
 struct sockaddr_l2 {
 	sa_family_t	l2_family;
@@ -236,6 +238,7 @@ struct l2cap_conn_rsp {
 /* channel indentifier */
 #define L2CAP_CID_SIGNALING	0x0001
 #define L2CAP_CID_CONN_LESS	0x0002
+#define L2CAP_CID_A2MP		0x0003
 #define L2CAP_CID_LE_DATA	0x0004
 #define L2CAP_CID_LE_SIGNALING	0x0005
 #define L2CAP_CID_SMP		0x0006
@@ -758,5 +761,8 @@ int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len,
 void l2cap_chan_busy(struct l2cap_chan *chan, int busy);
 int l2cap_chan_check_security(struct l2cap_chan *chan);
 void l2cap_chan_set_defaults(struct l2cap_chan *chan);
+int l2cap_ertm_init(struct l2cap_chan *chan);
+void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan);
+void l2cap_chan_del(struct l2cap_chan *chan, int err);
 
 #endif /* __L2CAP_H */
diff --git a/net/bluetooth/Makefile b/net/bluetooth/Makefile
index 2dc5a57..fa6d94a 100644
--- a/net/bluetooth/Makefile
+++ b/net/bluetooth/Makefile
@@ -9,4 +9,5 @@ obj-$(CONFIG_BT_CMTP)	+= cmtp/
 obj-$(CONFIG_BT_HIDP)	+= hidp/
 
 bluetooth-y := af_bluetooth.o hci_core.o hci_conn.o hci_event.o mgmt.o \
-	hci_sock.o hci_sysfs.o l2cap_core.o l2cap_sock.o smp.o sco.o lib.o
+	hci_sock.o hci_sysfs.o l2cap_core.o l2cap_sock.o smp.o sco.o lib.o \
+	a2mp.o
diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c
new file mode 100644
index 0000000..de455a2
--- /dev/null
+++ b/net/bluetooth/a2mp.c
@@ -0,0 +1,69 @@
+/*
+   Copyright (c) 2010,2011 Code Aurora Forum.  All rights reserved.
+   Copyright (c) 2011,2012 Intel Corp.
+
+   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.
+*/
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+#include <net/bluetooth/l2cap.h>
+
+static struct l2cap_ops a2mp_chan_ops = {
+	.name = "L2CAP A2MP channel",
+};
+
+static struct l2cap_chan *a2mp_chan_open(struct l2cap_conn *conn)
+{
+	struct l2cap_chan *chan;
+	int err;
+
+	chan = l2cap_chan_create();
+	if (!chan)
+		return NULL;
+
+	BT_DBG("chan %p", chan);
+
+	hci_conn_hold(conn->hcon);
+
+	chan->omtu = L2CAP_A2MP_DEFAULT_MTU;
+	chan->imtu = L2CAP_A2MP_DEFAULT_MTU;
+	chan->flush_to = L2CAP_DEFAULT_FLUSH_TO;
+
+	chan->ops = &a2mp_chan_ops;
+
+	l2cap_chan_set_defaults(chan);
+	chan->remote_max_tx = chan->max_tx;
+	chan->remote_tx_win = chan->tx_win;
+
+	chan->retrans_timeout = L2CAP_DEFAULT_RETRANS_TO;
+	chan->monitor_timeout = L2CAP_DEFAULT_MONITOR_TO;
+
+	skb_queue_head_init(&chan->tx_q);
+
+	chan->mode = L2CAP_MODE_ERTM;
+
+	err = l2cap_ertm_init(chan);
+	if (err < 0) {
+		l2cap_chan_del(chan, 0);
+		return NULL;
+	}
+
+	chan->conf_state = 0;
+
+	l2cap_chan_add(conn, chan);
+
+	chan->remote_mps = chan->omtu;
+	chan->mps = chan->omtu;
+
+	chan->state = BT_CONNECTED;
+
+	return chan;
+}
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 4f65a32..eb0ccef 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -484,14 +484,14 @@ static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
 	list_add(&chan->list, &conn->chan_l);
 }
 
-static void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
+void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
 {
 	mutex_lock(&conn->chan_lock);
 	__l2cap_chan_add(conn, chan);
 	mutex_unlock(&conn->chan_lock);
 }
 
-static void l2cap_chan_del(struct l2cap_chan *chan, int err)
+void l2cap_chan_del(struct l2cap_chan *chan, int err)
 {
 	struct l2cap_conn *conn = chan->conn;
 
@@ -2690,7 +2690,7 @@ static void l2cap_ack_timeout(struct work_struct *work)
 	l2cap_chan_put(chan);
 }
 
-static inline int l2cap_ertm_init(struct l2cap_chan *chan)
+int l2cap_ertm_init(struct l2cap_chan *chan)
 {
 	int err;
 
-- 
1.7.9.5


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

* [PATCHv4 02/17] Bluetooth: A2MP: AMP Manager basic functions
  2012-05-29 10:59 ` [PATCHv4 00/17] Bluetooth A2MP implementation Andrei Emeltchenko
  2012-05-29 10:59   ` [PATCHv4 01/17] Bluetooth: A2MP: Create A2MP channel Andrei Emeltchenko
@ 2012-05-29 10:59   ` Andrei Emeltchenko
  2012-05-29 10:59   ` [PATCHv4 03/17] Bluetooth: A2MP: Build and Send msg helpers Andrei Emeltchenko
                     ` (14 subsequent siblings)
  16 siblings, 0 replies; 104+ messages in thread
From: Andrei Emeltchenko @ 2012-05-29 10:59 UTC (permalink / raw)
  To: linux-bluetooth

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

Define AMP Manager and some basic functions.

Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
 include/net/bluetooth/a2mp.h     |   30 +++++++++++++++++++++
 include/net/bluetooth/hci_core.h |    1 +
 net/bluetooth/a2mp.c             |   54 ++++++++++++++++++++++++++++++++++++++
 net/bluetooth/hci_conn.c         |    4 +++
 4 files changed, 89 insertions(+)
 create mode 100644 include/net/bluetooth/a2mp.h

diff --git a/include/net/bluetooth/a2mp.h b/include/net/bluetooth/a2mp.h
new file mode 100644
index 0000000..ff47540
--- /dev/null
+++ b/include/net/bluetooth/a2mp.h
@@ -0,0 +1,30 @@
+/*
+   Copyright (c) 2010,2011 Code Aurora Forum.  All rights reserved.
+   Copyright (c) 2011,2012 Intel Corp.
+
+   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 __A2MP_H
+#define __A2MP_H
+
+struct amp_mgr {
+	struct l2cap_conn	*l2cap_conn;
+	struct l2cap_chan	*a2mp_chan;
+	struct kref		kref;
+	__u8			ident;
+	__u8			handle;
+	unsigned long		flags;
+};
+
+void amp_mgr_get(struct amp_mgr *mgr);
+int amp_mgr_put(struct amp_mgr *mgr);
+
+#endif /* __A2MP_H */
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index d584a47..6e64b76 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -332,6 +332,7 @@ struct hci_conn {
 	void		*l2cap_data;
 	void		*sco_data;
 	void		*smp_conn;
+	struct amp_mgr	*amp_mgr;
 
 	struct hci_conn	*link;
 
diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c
index de455a2..3c241c2 100644
--- a/net/bluetooth/a2mp.c
+++ b/net/bluetooth/a2mp.c
@@ -15,6 +15,7 @@
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
 #include <net/bluetooth/l2cap.h>
+#include <net/bluetooth/a2mp.h>
 
 static struct l2cap_ops a2mp_chan_ops = {
 	.name = "L2CAP A2MP channel",
@@ -67,3 +68,56 @@ static struct l2cap_chan *a2mp_chan_open(struct l2cap_conn *conn)
 
 	return chan;
 }
+
+/* AMP Manager functions */
+void amp_mgr_get(struct amp_mgr *mgr)
+{
+	BT_DBG("mgr %p", mgr);
+
+	kref_get(&mgr->kref);
+}
+
+static void amp_mgr_destroy(struct kref *kref)
+{
+	struct amp_mgr *mgr = container_of(kref, struct amp_mgr, kref);
+
+	BT_DBG("mgr %p", mgr);
+
+	kfree(mgr);
+}
+
+int amp_mgr_put(struct amp_mgr *mgr)
+{
+	BT_DBG("mgr %p", mgr);
+
+	return kref_put(&mgr->kref, &amp_mgr_destroy);
+}
+
+static struct amp_mgr *amp_mgr_create(struct l2cap_conn *conn)
+{
+	struct amp_mgr *mgr;
+	struct l2cap_chan *chan;
+
+	mgr = kzalloc(sizeof(*mgr), GFP_KERNEL);
+	if (!mgr)
+		return NULL;
+
+	BT_DBG("conn %p mgr %p", conn, mgr);
+
+	mgr->l2cap_conn = conn;
+
+	chan = a2mp_chan_open(conn);
+	if (!chan) {
+		kfree(mgr);
+		return NULL;
+	}
+
+	mgr->a2mp_chan = chan;
+	chan->data = mgr;
+
+	conn->hcon->amp_mgr = mgr;
+
+	kref_init(&mgr->kref);
+
+	return mgr;
+}
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index 126876d..1458667b 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -28,6 +28,7 @@
 
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
+#include <net/bluetooth/a2mp.h>
 
 static void hci_le_connect(struct hci_conn *conn)
 {
@@ -411,6 +412,9 @@ int hci_conn_del(struct hci_conn *conn)
 
 	hci_chan_list_flush(conn);
 
+	if (conn->amp_mgr)
+		amp_mgr_put(conn->amp_mgr);
+
 	hci_conn_hash_del(hdev, conn);
 	if (hdev->notify)
 		hdev->notify(hdev, HCI_NOTIFY_CONN_DEL);
-- 
1.7.9.5


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

* [PATCHv4 03/17] Bluetooth: A2MP: Build and Send msg helpers
  2012-05-29 10:59 ` [PATCHv4 00/17] Bluetooth A2MP implementation Andrei Emeltchenko
  2012-05-29 10:59   ` [PATCHv4 01/17] Bluetooth: A2MP: Create A2MP channel Andrei Emeltchenko
  2012-05-29 10:59   ` [PATCHv4 02/17] Bluetooth: A2MP: AMP Manager basic functions Andrei Emeltchenko
@ 2012-05-29 10:59   ` Andrei Emeltchenko
  2012-05-29 10:59   ` [PATCHv4 04/17] Bluetooth: A2MP: Add chan callbacks Andrei Emeltchenko
                     ` (13 subsequent siblings)
  16 siblings, 0 replies; 104+ messages in thread
From: Andrei Emeltchenko @ 2012-05-29 10:59 UTC (permalink / raw)
  To: linux-bluetooth

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

Helper function to build and send A2MP messages.

Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
 include/net/bluetooth/a2mp.h |    7 +++++++
 net/bluetooth/a2mp.c         |   46 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 53 insertions(+)

diff --git a/include/net/bluetooth/a2mp.h b/include/net/bluetooth/a2mp.h
index ff47540..654df60 100644
--- a/include/net/bluetooth/a2mp.h
+++ b/include/net/bluetooth/a2mp.h
@@ -24,6 +24,13 @@ struct amp_mgr {
 	unsigned long		flags;
 };
 
+struct a2mp_cmd {
+	__u8	code;
+	__u8	ident;
+	__le16	len;
+	__u8	data[0];
+} __packed;
+
 void amp_mgr_get(struct amp_mgr *mgr);
 int amp_mgr_put(struct amp_mgr *mgr);
 
diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c
index 3c241c2..53f49a0 100644
--- a/net/bluetooth/a2mp.c
+++ b/net/bluetooth/a2mp.c
@@ -17,6 +17,52 @@
 #include <net/bluetooth/l2cap.h>
 #include <net/bluetooth/a2mp.h>
 
+/* A2MP build & send command helper functions */
+static struct a2mp_cmd *__a2mp_build(u8 code, u8 ident, u16 len, void *data)
+{
+	struct a2mp_cmd *cmd;
+	int plen;
+
+	plen = sizeof(*cmd) + len;
+	cmd = kzalloc(plen, GFP_KERNEL);
+	if (!cmd)
+		return NULL;
+
+	cmd->code = code;
+	cmd->ident = ident;
+	cmd->len = cpu_to_le16(len);
+
+	memcpy(cmd->data, data, len);
+
+	return cmd;
+}
+
+static void a2mp_send(struct amp_mgr *mgr, u8 code, u8 ident, u16 len,
+		      void *data)
+{
+	struct l2cap_chan *chan = mgr->a2mp_chan;
+	struct a2mp_cmd *cmd;
+	u16 total_len = len + sizeof(*cmd);
+	struct kvec iv;
+	struct msghdr msg;
+
+	cmd = __a2mp_build(code, ident, len, data);
+	if (!cmd)
+		return;
+
+	iv.iov_base = cmd;
+	iv.iov_len = total_len;
+
+	memset(&msg, 0, sizeof(msg));
+
+	msg.msg_iov = (struct iovec *) &iv;
+	msg.msg_iovlen = 1;
+
+	l2cap_chan_send(chan, &msg, total_len, 0);
+
+	kfree(cmd);
+}
+
 static struct l2cap_ops a2mp_chan_ops = {
 	.name = "L2CAP A2MP channel",
 };
-- 
1.7.9.5


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

* [PATCHv4 04/17] Bluetooth: A2MP: Add chan callbacks
  2012-05-29 10:59 ` [PATCHv4 00/17] Bluetooth A2MP implementation Andrei Emeltchenko
                     ` (2 preceding siblings ...)
  2012-05-29 10:59   ` [PATCHv4 03/17] Bluetooth: A2MP: Build and Send msg helpers Andrei Emeltchenko
@ 2012-05-29 10:59   ` Andrei Emeltchenko
  2012-05-29 10:59   ` [PATCHv4 05/17] Bluetooth: A2MP: Definitions for A2MP commands Andrei Emeltchenko
                     ` (12 subsequent siblings)
  16 siblings, 0 replies; 104+ messages in thread
From: Andrei Emeltchenko @ 2012-05-29 10:59 UTC (permalink / raw)
  To: linux-bluetooth

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

Add L2CAP chan ops callbacks.

Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
 net/bluetooth/a2mp.c |   57 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 57 insertions(+)

diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c
index 53f49a0..4ba67dc 100644
--- a/net/bluetooth/a2mp.c
+++ b/net/bluetooth/a2mp.c
@@ -63,8 +63,65 @@ static void a2mp_send(struct amp_mgr *mgr, u8 code, u8 ident, u16 len,
 	kfree(cmd);
 }
 
+static void a2mp_chan_close_cb(struct l2cap_chan *chan)
+{
+	l2cap_chan_destroy(chan);
+}
+
+static void a2mp_chan_state_change_cb(struct l2cap_chan *chan, int state)
+{
+	struct amp_mgr *mgr = chan->data;
+
+	if (!mgr)
+		return;
+
+	chan = mgr->a2mp_chan;
+
+	BT_DBG("chan %p state %s", chan, state_to_string(state));
+
+	chan->state = state;
+
+	switch (state) {
+	case BT_CLOSED:
+		if (mgr)
+			amp_mgr_put(mgr);
+		break;
+	}
+}
+
+static struct sk_buff *a2mp_chan_alloc_skb_cb(struct l2cap_chan *chan,
+					      unsigned long len, int nb)
+{
+	return bt_skb_alloc(len, GFP_KERNEL);
+}
+
+static struct l2cap_chan *a2mp_chan_no_new_conn_cb(struct l2cap_chan *chan)
+{
+	BT_ERR("new_connection for chan %p not implemented", chan);
+
+	return NULL;
+}
+
+static void a2mp_chan_no_teardown_cb(struct l2cap_chan *chan, int err)
+{
+	BT_ERR("teardown for chan %p not implemented", chan);
+}
+
+static void a2mp_chan_no_ready(struct l2cap_chan *chan)
+{
+	BT_ERR("ready for chan %p not implemented", chan);
+}
+
 static struct l2cap_ops a2mp_chan_ops = {
 	.name = "L2CAP A2MP channel",
+	.close = a2mp_chan_close_cb,
+	.state_change = a2mp_chan_state_change_cb,
+	.alloc_skb = a2mp_chan_alloc_skb_cb,
+
+	/* Not implemented for A2MP */
+	.new_connection = a2mp_chan_no_new_conn_cb,
+	.teardown = a2mp_chan_no_teardown_cb,
+	.ready = a2mp_chan_no_ready,
 };
 
 static struct l2cap_chan *a2mp_chan_open(struct l2cap_conn *conn)
-- 
1.7.9.5


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

* [PATCHv4 05/17] Bluetooth: A2MP: Definitions for A2MP commands
  2012-05-29 10:59 ` [PATCHv4 00/17] Bluetooth A2MP implementation Andrei Emeltchenko
                     ` (3 preceding siblings ...)
  2012-05-29 10:59   ` [PATCHv4 04/17] Bluetooth: A2MP: Add chan callbacks Andrei Emeltchenko
@ 2012-05-29 10:59   ` Andrei Emeltchenko
  2012-05-29 10:59   ` [PATCHv4 06/17] Bluetooth: A2MP: Define A2MP status codes Andrei Emeltchenko
                     ` (11 subsequent siblings)
  16 siblings, 0 replies; 104+ messages in thread
From: Andrei Emeltchenko @ 2012-05-29 10:59 UTC (permalink / raw)
  To: linux-bluetooth

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

Define A2MP command IDs and packet structures.

Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
 include/net/bluetooth/a2mp.h |   73 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 73 insertions(+)

diff --git a/include/net/bluetooth/a2mp.h b/include/net/bluetooth/a2mp.h
index 654df60..7cbeb91 100644
--- a/include/net/bluetooth/a2mp.h
+++ b/include/net/bluetooth/a2mp.h
@@ -31,6 +31,79 @@ struct a2mp_cmd {
 	__u8	data[0];
 } __packed;
 
+/* A2MP command codes */
+#define A2MP_COMMAND_REJ         0x01
+struct a2mp_cmd_rej {
+	__le16	reason;
+	__u8	data[0];
+} __packed;
+
+#define A2MP_DISCOVER_REQ        0x02
+struct a2mp_discov_req {
+	__le16	mtu;
+	__le16	ext_feat;
+} __packed;
+
+struct a2mp_cl {
+	__u8	id;
+	__u8	type;
+	__u8	status;
+} __packed;
+
+#define A2MP_DISCOVER_RSP        0x03
+struct a2mp_discov_rsp {
+	__le16     mtu;
+	__le16     ext_feat;
+	struct a2mp_cl cl[0];
+} __packed;
+
+#define A2MP_CHANGE_NOTIFY       0x04
+#define A2MP_CHANGE_RSP          0x05
+
+#define A2MP_GETINFO_REQ         0x06
+struct a2mp_info_req {
+	__u8       id;
+} __packed;
+
+#define A2MP_GETINFO_RSP         0x07
+struct a2mp_info_rsp {
+	__u8	id;
+	__u8	status;
+	__le32	total_bw;
+	__le32	max_bw;
+	__le32	min_latency;
+	__le16	pal_cap;
+	__le16	assoc_size;
+} __packed;
+
+#define A2MP_GETAMPASSOC_REQ     0x08
+struct a2mp_amp_assoc_req {
+	__u8	id;
+} __packed;
+
+#define A2MP_GETAMPASSOC_RSP     0x09
+struct a2mp_amp_assoc_rsp {
+	__u8	id;
+	__u8	status;
+	__u8	amp_assoc[0];
+} __packed;
+
+#define A2MP_CREATEPHYSLINK_REQ  0x0A
+#define A2MP_DISCONNPHYSLINK_REQ 0x0C
+struct a2mp_physlink_req {
+	__u8	local_id;
+	__u8	remote_id;
+	__u8	amp_assoc[0];
+} __packed;
+
+#define A2MP_CREATEPHYSLINK_RSP  0x0B
+#define A2MP_DISCONNPHYSLINK_RSP 0x0D
+struct a2mp_physlink_rsp {
+	__u8	local_id;
+	__u8	remote_id;
+	__u8	status;
+} __packed;
+
 void amp_mgr_get(struct amp_mgr *mgr);
 int amp_mgr_put(struct amp_mgr *mgr);
 
-- 
1.7.9.5


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

* [PATCHv4 06/17] Bluetooth: A2MP: Define A2MP status codes
  2012-05-29 10:59 ` [PATCHv4 00/17] Bluetooth A2MP implementation Andrei Emeltchenko
                     ` (4 preceding siblings ...)
  2012-05-29 10:59   ` [PATCHv4 05/17] Bluetooth: A2MP: Definitions for A2MP commands Andrei Emeltchenko
@ 2012-05-29 10:59   ` Andrei Emeltchenko
  2012-05-29 10:59   ` [PATCHv4 07/17] Bluetooth: A2MP: Process A2MP messages Andrei Emeltchenko
                     ` (10 subsequent siblings)
  16 siblings, 0 replies; 104+ messages in thread
From: Andrei Emeltchenko @ 2012-05-29 10:59 UTC (permalink / raw)
  To: linux-bluetooth

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

A2MP status codes copied from Bluez patch sent by Peter Krystad
<pkrystad@codeaurora.org>.

Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
 include/net/bluetooth/a2mp.h |   10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/include/net/bluetooth/a2mp.h b/include/net/bluetooth/a2mp.h
index 7cbeb91..391acd7 100644
--- a/include/net/bluetooth/a2mp.h
+++ b/include/net/bluetooth/a2mp.h
@@ -104,6 +104,16 @@ struct a2mp_physlink_rsp {
 	__u8	status;
 } __packed;
 
+/* A2MP response status */
+#define A2MP_STATUS_SUCCESS			0x00
+#define A2MP_STATUS_INVALID_CTRL_ID		0x01
+#define A2MP_STATUS_UNABLE_START_LINK_CREATION	0x02
+#define A2MP_STATUS_NO_PHYSICAL_LINK_EXISTS	0x02
+#define A2MP_STATUS_COLLISION_OCCURED		0x03
+#define A2MP_STATUS_DISCONN_REQ_RECVD		0x04
+#define A2MP_STATUS_PHYS_LINK_EXISTS		0x05
+#define A2MP_STATUS_SECURITY_VIOLATION		0x06
+
 void amp_mgr_get(struct amp_mgr *mgr);
 int amp_mgr_put(struct amp_mgr *mgr);
 
-- 
1.7.9.5


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

* [PATCHv4 07/17] Bluetooth: A2MP: Process A2MP messages
  2012-05-29 10:59 ` [PATCHv4 00/17] Bluetooth A2MP implementation Andrei Emeltchenko
                     ` (5 preceding siblings ...)
  2012-05-29 10:59   ` [PATCHv4 06/17] Bluetooth: A2MP: Define A2MP status codes Andrei Emeltchenko
@ 2012-05-29 10:59   ` Andrei Emeltchenko
  2012-05-29 10:59   ` [PATCHv4 08/17] Bluetooth: A2MP: Process A2MP Command Reject Andrei Emeltchenko
                     ` (9 subsequent siblings)
  16 siblings, 0 replies; 104+ messages in thread
From: Andrei Emeltchenko @ 2012-05-29 10:59 UTC (permalink / raw)
  To: linux-bluetooth

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

Implement basic processing for AMP Manager Protocol (A2MP).

Example below shows processing unrecognized command.
...
> ACL data: handle 11 flags 0x02 dlen 12
    A2MP: code 0x00 ident 3 len 0
< ACL data: handle 11 flags 0x00 dlen 14
    A2MP: Command Reject: reason (0) - Command not recognized
...

Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
 net/bluetooth/a2mp.c |   65 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 65 insertions(+)

diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c
index 4ba67dc..d07a8a5 100644
--- a/net/bluetooth/a2mp.c
+++ b/net/bluetooth/a2mp.c
@@ -63,6 +63,70 @@ static void a2mp_send(struct amp_mgr *mgr, u8 code, u8 ident, u16 len,
 	kfree(cmd);
 }
 
+/* Handle A2MP signalling */
+static int a2mp_chan_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb)
+{
+	struct a2mp_cmd *hdr = (void *) skb->data;
+	struct amp_mgr *mgr = chan->data;
+	int err = 0;
+
+	amp_mgr_get(mgr);
+
+	while (skb->len >= sizeof(*hdr)) {
+		struct a2mp_cmd *hdr = (void *) skb->data;
+		u16 len = le16_to_cpu(hdr->len);
+
+		BT_DBG("code 0x%02x id %d len %d", hdr->code, hdr->ident, len);
+
+		skb_pull(skb, sizeof(*hdr));
+
+		if (len > skb->len || !hdr->ident) {
+			err = -EINVAL;
+			break;
+		}
+
+		mgr->ident = hdr->ident;
+
+		switch (hdr->code) {
+		case A2MP_COMMAND_REJ:
+		case A2MP_DISCOVER_REQ:
+		case A2MP_CHANGE_NOTIFY:
+		case A2MP_GETINFO_REQ:
+		case A2MP_GETAMPASSOC_REQ:
+		case A2MP_CREATEPHYSLINK_REQ:
+		case A2MP_DISCONNPHYSLINK_REQ:
+		case A2MP_CHANGE_RSP:
+		case A2MP_DISCOVER_RSP:
+		case A2MP_GETINFO_RSP:
+		case A2MP_GETAMPASSOC_RSP:
+		case A2MP_CREATEPHYSLINK_RSP:
+		case A2MP_DISCONNPHYSLINK_RSP:
+		default:
+			BT_ERR("Unknown A2MP sig cmd 0x%2.2x", hdr->code);
+			err = -EINVAL;
+			break;
+		}
+	}
+
+	if (err) {
+		struct a2mp_cmd_rej rej;
+		rej.reason = __constant_cpu_to_le16(0);
+
+		BT_DBG("Send A2MP Rej: cmd 0x%2.2x err %d", hdr->code, err);
+
+		a2mp_send(mgr, A2MP_COMMAND_REJ, hdr->ident, sizeof(rej),
+			  &rej);
+	}
+
+	/* Always free skb and return success error code to prevent
+	   from sending L2CAP Disconnect over A2MP channel */
+	kfree_skb(skb);
+
+	amp_mgr_put(mgr);
+
+	return 0;
+}
+
 static void a2mp_chan_close_cb(struct l2cap_chan *chan)
 {
 	l2cap_chan_destroy(chan);
@@ -114,6 +178,7 @@ static void a2mp_chan_no_ready(struct l2cap_chan *chan)
 
 static struct l2cap_ops a2mp_chan_ops = {
 	.name = "L2CAP A2MP channel",
+	.recv = a2mp_chan_recv_cb,
 	.close = a2mp_chan_close_cb,
 	.state_change = a2mp_chan_state_change_cb,
 	.alloc_skb = a2mp_chan_alloc_skb_cb,
-- 
1.7.9.5


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

* [PATCHv4 08/17] Bluetooth: A2MP: Process A2MP Command Reject
  2012-05-29 10:59 ` [PATCHv4 00/17] Bluetooth A2MP implementation Andrei Emeltchenko
                     ` (6 preceding siblings ...)
  2012-05-29 10:59   ` [PATCHv4 07/17] Bluetooth: A2MP: Process A2MP messages Andrei Emeltchenko
@ 2012-05-29 10:59   ` Andrei Emeltchenko
  2012-05-29 10:59   ` [PATCHv4 09/17] Bluetooth: A2MP: Process A2MP Discover Request Andrei Emeltchenko
                     ` (8 subsequent siblings)
  16 siblings, 0 replies; 104+ messages in thread
From: Andrei Emeltchenko @ 2012-05-29 10:59 UTC (permalink / raw)
  To: linux-bluetooth

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

Placeholder for future A2MP Command Reject handler.

Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
 net/bluetooth/a2mp.c |   19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c
index d07a8a5..0aac317 100644
--- a/net/bluetooth/a2mp.c
+++ b/net/bluetooth/a2mp.c
@@ -63,6 +63,22 @@ static void a2mp_send(struct amp_mgr *mgr, u8 code, u8 ident, u16 len,
 	kfree(cmd);
 }
 
+/* Processing A2MP messages */
+static int a2mp_command_rej(struct amp_mgr *mgr, struct sk_buff *skb,
+			    struct a2mp_cmd *hdr)
+{
+	struct a2mp_cmd_rej *rej = (void *) skb->data;
+
+	if (le16_to_cpu(hdr->len) < sizeof(*rej))
+		return -EINVAL;
+
+	BT_DBG("ident %d reason %d", hdr->ident, le16_to_cpu(rej->reason));
+
+	skb_pull(skb, sizeof(*rej));
+
+	return 0;
+}
+
 /* Handle A2MP signalling */
 static int a2mp_chan_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb)
 {
@@ -89,6 +105,9 @@ static int a2mp_chan_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb)
 
 		switch (hdr->code) {
 		case A2MP_COMMAND_REJ:
+			a2mp_command_rej(mgr, skb, hdr);
+			break;
+
 		case A2MP_DISCOVER_REQ:
 		case A2MP_CHANGE_NOTIFY:
 		case A2MP_GETINFO_REQ:
-- 
1.7.9.5


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

* [PATCHv4 09/17] Bluetooth: A2MP: Process A2MP Discover Request
  2012-05-29 10:59 ` [PATCHv4 00/17] Bluetooth A2MP implementation Andrei Emeltchenko
                     ` (7 preceding siblings ...)
  2012-05-29 10:59   ` [PATCHv4 08/17] Bluetooth: A2MP: Process A2MP Command Reject Andrei Emeltchenko
@ 2012-05-29 10:59   ` Andrei Emeltchenko
  2012-05-29 10:59   ` [PATCHv4 10/17] Bluetooth: A2MP: Process A2MP Change Notify Andrei Emeltchenko
                     ` (7 subsequent siblings)
  16 siblings, 0 replies; 104+ messages in thread
From: Andrei Emeltchenko @ 2012-05-29 10:59 UTC (permalink / raw)
  To: linux-bluetooth

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

Adds helper functions to count HCI devs and process A2MP Discover
Request, code makes sure that first controller in the list is
BREDR one. Trace is shown below:

...
> ACL data: handle 11 flags 0x02 dlen 16
    A2MP: Discover req: mtu/mps 670 mask: 0x0000
< ACL data: handle 11 flags 0x00 dlen 22
    A2MP: Discover rsp: mtu/mps 670 mask: 0x0000
      Controller list:
        id 0 type 0 (BR-EDR) status 0x01 (Bluetooth only)
        id 1 type 1 (802.11 AMP) status 0x01 (Bluetooth only)
...

Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
 include/net/bluetooth/a2mp.h     |    2 +
 include/net/bluetooth/hci.h      |    3 ++
 include/net/bluetooth/hci_core.h |   13 ++++++
 net/bluetooth/a2mp.c             |   85 ++++++++++++++++++++++++++++++++++++++
 4 files changed, 103 insertions(+)

diff --git a/include/net/bluetooth/a2mp.h b/include/net/bluetooth/a2mp.h
index 391acd7..96f9cc2 100644
--- a/include/net/bluetooth/a2mp.h
+++ b/include/net/bluetooth/a2mp.h
@@ -15,6 +15,8 @@
 #ifndef __A2MP_H
 #define __A2MP_H
 
+#define A2MP_FEAT_EXT	0x8000
+
 struct amp_mgr {
 	struct l2cap_conn	*l2cap_conn;
 	struct l2cap_chan	*a2mp_chan;
diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index de09a26..66af2c6 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -59,6 +59,9 @@
 #define HCI_BREDR	0x00
 #define HCI_AMP		0x01
 
+/* First BR/EDR Controller shall have ID = 0 */
+#define HCI_BREDR_ID	0
+
 /* HCI device quirks */
 enum {
 	HCI_QUIRK_RESET_ON_CLOSE,
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 6e64b76..20fd573 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -641,6 +641,19 @@ static inline void hci_set_drvdata(struct hci_dev *hdev, void *data)
 	dev_set_drvdata(&hdev->dev, data);
 }
 
+/* hci_dev_list shall be locked */
+static inline uint8_t __hci_num_ctrl(void)
+{
+	uint8_t count = 0;
+	struct list_head *p;
+
+	list_for_each(p, &hci_dev_list) {
+		count++;
+	}
+
+	return count;
+}
+
 struct hci_dev *hci_dev_get(int index);
 struct hci_dev *hci_get_route(bdaddr_t *src, bdaddr_t *dst);
 
diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c
index 0aac317..51927b6 100644
--- a/net/bluetooth/a2mp.c
+++ b/net/bluetooth/a2mp.c
@@ -63,6 +63,36 @@ static void a2mp_send(struct amp_mgr *mgr, u8 code, u8 ident, u16 len,
 	kfree(cmd);
 }
 
+static inline void __a2mp_cl_bredr(struct a2mp_cl *cl)
+{
+	cl->id = 0;
+	cl->type = 0;
+	cl->status = 1;
+}
+
+/* hci_dev_list shall be locked */
+static void __a2mp_add_cl(struct amp_mgr *mgr, struct a2mp_cl *cl, u8 num_ctrl)
+{
+	int i = 0;
+	struct hci_dev *hdev;
+
+	__a2mp_cl_bredr(cl);
+
+	list_for_each_entry(hdev, &hci_dev_list, list) {
+		/* Iterate through AMP controllers */
+		if (hdev->id == HCI_BREDR_ID)
+			continue;
+
+		/* Starting from second entry */
+		if (++i >= num_ctrl)
+			return;
+
+		cl[i].id = hdev->id;
+		cl[i].type = hdev->amp_type;
+		cl[i].status = hdev->amp_status;
+	}
+}
+
 /* Processing A2MP messages */
 static int a2mp_command_rej(struct amp_mgr *mgr, struct sk_buff *skb,
 			    struct a2mp_cmd *hdr)
@@ -79,6 +109,58 @@ static int a2mp_command_rej(struct amp_mgr *mgr, struct sk_buff *skb,
 	return 0;
 }
 
+static int a2mp_discover_req(struct amp_mgr *mgr, struct sk_buff *skb,
+			     struct a2mp_cmd *hdr)
+{
+	struct a2mp_discov_req *req = (void *) skb->data;
+	u16 len = le16_to_cpu(hdr->len);
+	struct a2mp_discov_rsp *rsp;
+	u16 ext_feat;
+	u8 num_ctrl;
+
+	if (len < sizeof(*req))
+		return -EINVAL;
+
+	skb_pull(skb, sizeof(*req));
+
+	ext_feat = le16_to_cpu(req->ext_feat);
+
+	BT_DBG("mtu %d efm 0x%4.4x", le16_to_cpu(req->mtu), ext_feat);
+
+	/* check that packet is not broken for now */
+	while (ext_feat & A2MP_FEAT_EXT) {
+		if (len < sizeof(ext_feat))
+			return -EINVAL;
+
+		ext_feat = get_unaligned_le16(skb->data);
+		BT_DBG("efm 0x%4.4x", ext_feat);
+		len -= sizeof(ext_feat);
+		skb_pull(skb, sizeof(ext_feat));
+	}
+
+	read_lock(&hci_dev_list_lock);
+
+	num_ctrl = __hci_num_ctrl();
+	len = num_ctrl * sizeof(struct a2mp_cl) + sizeof(*rsp);
+	rsp = kmalloc(len, GFP_ATOMIC);
+	if (!rsp) {
+		read_unlock(&hci_dev_list_lock);
+		return -ENOMEM;
+	}
+
+	rsp->mtu = __constant_cpu_to_le16(L2CAP_A2MP_DEFAULT_MTU);
+	rsp->ext_feat = 0;
+
+	__a2mp_add_cl(mgr, rsp->cl, num_ctrl);
+
+	read_unlock(&hci_dev_list_lock);
+
+	a2mp_send(mgr, A2MP_DISCOVER_RSP, hdr->ident, len, rsp);
+
+	kfree(rsp);
+	return 0;
+}
+
 /* Handle A2MP signalling */
 static int a2mp_chan_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb)
 {
@@ -109,6 +191,9 @@ static int a2mp_chan_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb)
 			break;
 
 		case A2MP_DISCOVER_REQ:
+			err = a2mp_discover_req(mgr, skb, hdr);
+			break;
+
 		case A2MP_CHANGE_NOTIFY:
 		case A2MP_GETINFO_REQ:
 		case A2MP_GETAMPASSOC_REQ:
-- 
1.7.9.5


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

* [PATCHv4 10/17] Bluetooth: A2MP: Process A2MP Change Notify
  2012-05-29 10:59 ` [PATCHv4 00/17] Bluetooth A2MP implementation Andrei Emeltchenko
                     ` (8 preceding siblings ...)
  2012-05-29 10:59   ` [PATCHv4 09/17] Bluetooth: A2MP: Process A2MP Discover Request Andrei Emeltchenko
@ 2012-05-29 10:59   ` Andrei Emeltchenko
  2012-05-29 10:59   ` [PATCHv4 11/17] Bluetooth: A2MP: Process A2MP Get Info Request Andrei Emeltchenko
                     ` (6 subsequent siblings)
  16 siblings, 0 replies; 104+ messages in thread
From: Andrei Emeltchenko @ 2012-05-29 10:59 UTC (permalink / raw)
  To: linux-bluetooth

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

Placeholder for A2MP Change Notify handler.

Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
 net/bluetooth/a2mp.c |   19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c
index 51927b6..b610f13 100644
--- a/net/bluetooth/a2mp.c
+++ b/net/bluetooth/a2mp.c
@@ -161,6 +161,22 @@ static int a2mp_discover_req(struct amp_mgr *mgr, struct sk_buff *skb,
 	return 0;
 }
 
+static int a2mp_change_notify(struct amp_mgr *mgr, struct sk_buff *skb,
+			      struct a2mp_cmd *hdr)
+{
+	struct a2mp_cl *cl = (void *) skb->data;
+
+	while (skb->len >= sizeof(*cl)) {
+		BT_DBG("Controller id %d type %d status %d", cl->id, cl->type,
+		       cl->status);
+		cl = (struct a2mp_cl *) skb_pull(skb, sizeof(*cl));
+	}
+
+	/* TODO send A2MP_CHANGE_RSP */
+
+	return 0;
+}
+
 /* Handle A2MP signalling */
 static int a2mp_chan_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb)
 {
@@ -195,6 +211,9 @@ static int a2mp_chan_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb)
 			break;
 
 		case A2MP_CHANGE_NOTIFY:
+			err = a2mp_change_notify(mgr, skb, hdr);
+			break;
+
 		case A2MP_GETINFO_REQ:
 		case A2MP_GETAMPASSOC_REQ:
 		case A2MP_CREATEPHYSLINK_REQ:
-- 
1.7.9.5


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

* [PATCHv4 11/17] Bluetooth: A2MP: Process A2MP Get Info Request
  2012-05-29 10:59 ` [PATCHv4 00/17] Bluetooth A2MP implementation Andrei Emeltchenko
                     ` (9 preceding siblings ...)
  2012-05-29 10:59   ` [PATCHv4 10/17] Bluetooth: A2MP: Process A2MP Change Notify Andrei Emeltchenko
@ 2012-05-29 10:59   ` Andrei Emeltchenko
  2012-05-29 10:59   ` [PATCHv4 12/17] Bluetooth: A2MP: Process A2MP Get AMP Assoc Request Andrei Emeltchenko
                     ` (5 subsequent siblings)
  16 siblings, 0 replies; 104+ messages in thread
From: Andrei Emeltchenko @ 2012-05-29 10:59 UTC (permalink / raw)
  To: linux-bluetooth

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

Process A2MP Get Info Request.
Example of trace log for invalid controller id is shown below:

...
> ACL data: handle 11 flags 0x02 dlen 13
    A2MP: Get Info req: id 238
< ACL data: handle 11 flags 0x00 dlen 30
    A2MP: Get Info rsp: id 238 status (1) Invalid Controller ID
...

Note that If the Status field is set to Invalid Controller ID all subsequent
fields in the AMP Get Info Response shall be ignored by the receiver.

Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
 net/bluetooth/a2mp.c |   37 +++++++++++++++++++++++++++++++++++++
 1 file changed, 37 insertions(+)

diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c
index b610f13..38a0b38 100644
--- a/net/bluetooth/a2mp.c
+++ b/net/bluetooth/a2mp.c
@@ -177,6 +177,40 @@ static int a2mp_change_notify(struct amp_mgr *mgr, struct sk_buff *skb,
 	return 0;
 }
 
+static int a2mp_getinfo_req(struct amp_mgr *mgr, struct sk_buff *skb,
+			    struct a2mp_cmd *hdr)
+{
+	struct a2mp_info_req *req  = (void *) skb->data;
+	struct a2mp_info_rsp rsp;
+	struct hci_dev *hdev;
+
+	if (le16_to_cpu(hdr->len) < sizeof(*req))
+		return -EINVAL;
+
+	BT_DBG("id %d", req->id);
+
+	rsp.id = req->id;
+	rsp.status = A2MP_STATUS_INVALID_CTRL_ID;
+
+	hdev = hci_dev_get(req->id);
+	if (hdev && hdev->amp_type != HCI_BREDR) {
+		rsp.status = 0;
+		rsp.total_bw = cpu_to_le32(hdev->amp_total_bw);
+		rsp.max_bw = cpu_to_le32(hdev->amp_max_bw);
+		rsp.min_latency = cpu_to_le32(hdev->amp_min_latency);
+		rsp.pal_cap = cpu_to_le16(hdev->amp_pal_cap);
+		rsp.assoc_size = cpu_to_le16(hdev->amp_assoc_size);
+	}
+
+	if (hdev)
+		hci_dev_put(hdev);
+
+	a2mp_send(mgr, A2MP_GETINFO_RSP, hdr->ident, sizeof(rsp), &rsp);
+
+	skb_pull(skb, sizeof(*req));
+	return 0;
+}
+
 /* Handle A2MP signalling */
 static int a2mp_chan_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb)
 {
@@ -215,6 +249,9 @@ static int a2mp_chan_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb)
 			break;
 
 		case A2MP_GETINFO_REQ:
+			err = a2mp_getinfo_req(mgr, skb, hdr);
+			break;
+
 		case A2MP_GETAMPASSOC_REQ:
 		case A2MP_CREATEPHYSLINK_REQ:
 		case A2MP_DISCONNPHYSLINK_REQ:
-- 
1.7.9.5


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

* [PATCHv4 12/17] Bluetooth: A2MP: Process A2MP Get AMP Assoc Request
  2012-05-29 10:59 ` [PATCHv4 00/17] Bluetooth A2MP implementation Andrei Emeltchenko
                     ` (10 preceding siblings ...)
  2012-05-29 10:59   ` [PATCHv4 11/17] Bluetooth: A2MP: Process A2MP Get Info Request Andrei Emeltchenko
@ 2012-05-29 10:59   ` Andrei Emeltchenko
  2012-05-29 10:59   ` [PATCHv4 13/17] Bluetooth: A2MP: Process A2MP Create Physlink Request Andrei Emeltchenko
                     ` (4 subsequent siblings)
  16 siblings, 0 replies; 104+ messages in thread
From: Andrei Emeltchenko @ 2012-05-29 10:59 UTC (permalink / raw)
  To: linux-bluetooth

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

Example trace when receiving AMP Assoc Request with wrong AMP id.
...
> ACL data: handle 11 flags 0x02 dlen 13
    A2MP: Get AMP Assoc req: id 238
< ACL data: handle 11 flags 0x00 dlen 14
    A2MP: Get AMP Assoc rsp: id 238 status (1) Invalid Controller ID
      assoc data:
...

Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
 net/bluetooth/a2mp.c |   35 +++++++++++++++++++++++++++++++++++
 1 file changed, 35 insertions(+)

diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c
index 38a0b38..63c5394 100644
--- a/net/bluetooth/a2mp.c
+++ b/net/bluetooth/a2mp.c
@@ -211,6 +211,38 @@ static int a2mp_getinfo_req(struct amp_mgr *mgr, struct sk_buff *skb,
 	return 0;
 }
 
+static int a2mp_getampassoc_req(struct amp_mgr *mgr, struct sk_buff *skb,
+				struct a2mp_cmd *hdr)
+{
+	struct a2mp_amp_assoc_req *req = (void *) skb->data;
+	struct hci_dev *hdev;
+
+	if (le16_to_cpu(hdr->len) < sizeof(*req))
+		return -EINVAL;
+
+	BT_DBG("id %d", req->id);
+
+	hdev = hci_dev_get(req->id);
+	if (!hdev || hdev->amp_type == HCI_BREDR) {
+		struct a2mp_amp_assoc_rsp rsp;
+		rsp.id = req->id;
+		rsp.status = A2MP_STATUS_INVALID_CTRL_ID;
+
+		a2mp_send(mgr, A2MP_GETAMPASSOC_RSP, hdr->ident, sizeof(rsp),
+			  &rsp);
+		goto clean;
+	}
+
+	/* Placeholder for HCI Read AMP Assoc */
+
+clean:
+	if (hdev)
+		hci_dev_put(hdev);
+
+	skb_pull(skb, sizeof(*req));
+	return 0;
+}
+
 /* Handle A2MP signalling */
 static int a2mp_chan_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb)
 {
@@ -253,6 +285,9 @@ static int a2mp_chan_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb)
 			break;
 
 		case A2MP_GETAMPASSOC_REQ:
+			err = a2mp_getampassoc_req(mgr, skb, hdr);
+			break;
+
 		case A2MP_CREATEPHYSLINK_REQ:
 		case A2MP_DISCONNPHYSLINK_REQ:
 		case A2MP_CHANGE_RSP:
-- 
1.7.9.5


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

* [PATCHv4 13/17] Bluetooth: A2MP: Process A2MP Create Physlink Request
  2012-05-29 10:59 ` [PATCHv4 00/17] Bluetooth A2MP implementation Andrei Emeltchenko
                     ` (11 preceding siblings ...)
  2012-05-29 10:59   ` [PATCHv4 12/17] Bluetooth: A2MP: Process A2MP Get AMP Assoc Request Andrei Emeltchenko
@ 2012-05-29 10:59   ` Andrei Emeltchenko
  2012-05-29 10:59   ` [PATCHv4 14/17] Bluetooth: A2MP: Process A2MP Disc " Andrei Emeltchenko
                     ` (3 subsequent siblings)
  16 siblings, 0 replies; 104+ messages in thread
From: Andrei Emeltchenko @ 2012-05-29 10:59 UTC (permalink / raw)
  To: linux-bluetooth

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

Placeholder for A2MP Create Physlink Request.
Handles requests with invalid controler id as shown below:

...
> ACL data: handle 11 flags 0x02 dlen 50
    A2MP: Create Physical Link req: local id 1 remote id 85
      Assoc data:
        <skipped>
< ACL data: handle 11 flags 0x00 dlen 15
    A2MP: Create Physical Link rsp: local id 85 remote id 1 status 1
      Invalid Controller ID
...

Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
 net/bluetooth/a2mp.c |   40 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 40 insertions(+)

diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c
index 63c5394..870ef009 100644
--- a/net/bluetooth/a2mp.c
+++ b/net/bluetooth/a2mp.c
@@ -243,6 +243,43 @@ clean:
 	return 0;
 }
 
+static int a2mp_createphyslink_req(struct amp_mgr *mgr, struct sk_buff *skb,
+				   struct a2mp_cmd *hdr)
+{
+	struct a2mp_physlink_req *req = (void *) skb->data;
+
+	struct a2mp_physlink_rsp rsp;
+	struct hci_dev *hdev;
+
+	if (le16_to_cpu(hdr->len) < sizeof(*req))
+		return -EINVAL;
+
+	BT_DBG("local_id %d, remote_id %d", req->local_id, req->remote_id);
+
+	rsp.local_id = req->remote_id;
+	rsp.remote_id = req->local_id;
+
+	hdev = hci_dev_get(req->remote_id);
+	if (!hdev || hdev->amp_type != HCI_AMP) {
+		rsp.status = A2MP_STATUS_INVALID_CTRL_ID;
+		goto send_rsp;
+	}
+
+	/* TODO process physlink create */
+
+	rsp.status = A2MP_STATUS_SUCCESS;
+
+send_rsp:
+	if (hdev)
+		hci_dev_put(hdev);
+
+	a2mp_send(mgr, A2MP_CREATEPHYSLINK_RSP, hdr->ident, sizeof(rsp),
+		  &rsp);
+
+	skb_pull(skb, le16_to_cpu(hdr->len));
+	return 0;
+}
+
 /* Handle A2MP signalling */
 static int a2mp_chan_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb)
 {
@@ -289,6 +326,9 @@ static int a2mp_chan_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb)
 			break;
 
 		case A2MP_CREATEPHYSLINK_REQ:
+			err = a2mp_createphyslink_req(mgr, skb, hdr);
+			break;
+
 		case A2MP_DISCONNPHYSLINK_REQ:
 		case A2MP_CHANGE_RSP:
 		case A2MP_DISCOVER_RSP:
-- 
1.7.9.5


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

* [PATCHv4 14/17] Bluetooth: A2MP: Process A2MP Disc Physlink Request
  2012-05-29 10:59 ` [PATCHv4 00/17] Bluetooth A2MP implementation Andrei Emeltchenko
                     ` (12 preceding siblings ...)
  2012-05-29 10:59   ` [PATCHv4 13/17] Bluetooth: A2MP: Process A2MP Create Physlink Request Andrei Emeltchenko
@ 2012-05-29 10:59   ` Andrei Emeltchenko
  2012-05-29 10:59   ` [PATCHv4 15/17] Bluetooth: A2MP: Process A2MP Command Responses Andrei Emeltchenko
                     ` (2 subsequent siblings)
  16 siblings, 0 replies; 104+ messages in thread
From: Andrei Emeltchenko @ 2012-05-29 10:59 UTC (permalink / raw)
  To: linux-bluetooth

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

Placeholder for A2MP Disconnect Physlink Request.

Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
 net/bluetooth/a2mp.c |   36 ++++++++++++++++++++++++++++++++++++
 1 file changed, 36 insertions(+)

diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c
index 870ef009..0d3e0d9 100644
--- a/net/bluetooth/a2mp.c
+++ b/net/bluetooth/a2mp.c
@@ -280,6 +280,39 @@ send_rsp:
 	return 0;
 }
 
+static int a2mp_discphyslink_req(struct amp_mgr *mgr, struct sk_buff *skb,
+				 struct a2mp_cmd *hdr)
+{
+	struct a2mp_physlink_req *req = (void *) skb->data;
+	struct a2mp_physlink_rsp rsp;
+	struct hci_dev *hdev;
+
+	if (le16_to_cpu(hdr->len) < sizeof(*req))
+		return -EINVAL;
+
+	BT_DBG("local_id %d remote_id %d", req->local_id, req->remote_id);
+
+	rsp.local_id = req->remote_id;
+	rsp.remote_id = req->local_id;
+	rsp.status = A2MP_STATUS_SUCCESS;
+
+	hdev = hci_dev_get(req->local_id);
+	if (!hdev) {
+		rsp.status = A2MP_STATUS_INVALID_CTRL_ID;
+		goto send_rsp;
+	}
+
+	/* TODO Disconnect Phys Link here */
+
+	hci_dev_put(hdev);
+
+send_rsp:
+	a2mp_send(mgr, A2MP_DISCONNPHYSLINK_RSP, hdr->ident, sizeof(rsp), &rsp);
+
+	skb_pull(skb, sizeof(*req));
+	return 0;
+}
+
 /* Handle A2MP signalling */
 static int a2mp_chan_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb)
 {
@@ -330,6 +363,9 @@ static int a2mp_chan_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb)
 			break;
 
 		case A2MP_DISCONNPHYSLINK_REQ:
+			err = a2mp_discphyslink_req(mgr, skb, hdr);
+			break;
+
 		case A2MP_CHANGE_RSP:
 		case A2MP_DISCOVER_RSP:
 		case A2MP_GETINFO_RSP:
-- 
1.7.9.5


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

* [PATCHv4 15/17] Bluetooth: A2MP: Process A2MP Command Responses
  2012-05-29 10:59 ` [PATCHv4 00/17] Bluetooth A2MP implementation Andrei Emeltchenko
                     ` (13 preceding siblings ...)
  2012-05-29 10:59   ` [PATCHv4 14/17] Bluetooth: A2MP: Process A2MP Disc " Andrei Emeltchenko
@ 2012-05-29 10:59   ` Andrei Emeltchenko
  2012-05-29 10:59   ` [PATCHv4 16/17] Bluetooth: A2MP: Handling fixed channels Andrei Emeltchenko
  2012-05-29 10:59   ` [PATCHv4 17/17] Bluetooth: A2MP: Manage incoming connections Andrei Emeltchenko
  16 siblings, 0 replies; 104+ messages in thread
From: Andrei Emeltchenko @ 2012-05-29 10:59 UTC (permalink / raw)
  To: linux-bluetooth

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

Process A2MP responses, print cmd code and ident for now.

Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
 net/bluetooth/a2mp.c |   12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c
index 0d3e0d9..1076ce3 100644
--- a/net/bluetooth/a2mp.c
+++ b/net/bluetooth/a2mp.c
@@ -313,6 +313,15 @@ send_rsp:
 	return 0;
 }
 
+static inline int a2mp_cmd_rsp(struct amp_mgr *mgr, struct sk_buff *skb,
+			       struct a2mp_cmd *hdr)
+{
+	BT_DBG("ident %d code %d", hdr->ident, hdr->code);
+
+	skb_pull(skb, le16_to_cpu(hdr->len));
+	return 0;
+}
+
 /* Handle A2MP signalling */
 static int a2mp_chan_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb)
 {
@@ -372,6 +381,9 @@ static int a2mp_chan_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb)
 		case A2MP_GETAMPASSOC_RSP:
 		case A2MP_CREATEPHYSLINK_RSP:
 		case A2MP_DISCONNPHYSLINK_RSP:
+			err = a2mp_cmd_rsp(mgr, skb, hdr);
+			break;
+
 		default:
 			BT_ERR("Unknown A2MP sig cmd 0x%2.2x", hdr->code);
 			err = -EINVAL;
-- 
1.7.9.5


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

* [PATCHv4 16/17] Bluetooth: A2MP: Handling fixed channels
  2012-05-29 10:59 ` [PATCHv4 00/17] Bluetooth A2MP implementation Andrei Emeltchenko
                     ` (14 preceding siblings ...)
  2012-05-29 10:59   ` [PATCHv4 15/17] Bluetooth: A2MP: Process A2MP Command Responses Andrei Emeltchenko
@ 2012-05-29 10:59   ` Andrei Emeltchenko
  2012-05-29 10:59   ` [PATCHv4 17/17] Bluetooth: A2MP: Manage incoming connections Andrei Emeltchenko
  16 siblings, 0 replies; 104+ messages in thread
From: Andrei Emeltchenko @ 2012-05-29 10:59 UTC (permalink / raw)
  To: linux-bluetooth

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

A2MP fixed channel do not have sk

Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
 include/net/bluetooth/l2cap.h |    1 +
 net/bluetooth/a2mp.c          |    3 +--
 net/bluetooth/l2cap_core.c    |   17 +++++++++++++++++
 3 files changed, 19 insertions(+), 2 deletions(-)

diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index aaba222..a00b43e 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -581,6 +581,7 @@ struct l2cap_conn {
 #define L2CAP_CHAN_RAW			1
 #define L2CAP_CHAN_CONN_LESS		2
 #define L2CAP_CHAN_CONN_ORIENTED	3
+#define L2CAP_CHAN_CONN_FIX_A2MP	4
 
 /* ----- L2CAP socket info ----- */
 #define l2cap_pi(sk) ((struct l2cap_pinfo *) sk)
diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c
index 1076ce3..2019fe3 100644
--- a/net/bluetooth/a2mp.c
+++ b/net/bluetooth/a2mp.c
@@ -485,8 +485,7 @@ static struct l2cap_chan *a2mp_chan_open(struct l2cap_conn *conn)
 
 	hci_conn_hold(conn->hcon);
 
-	chan->omtu = L2CAP_A2MP_DEFAULT_MTU;
-	chan->imtu = L2CAP_A2MP_DEFAULT_MTU;
+	chan->chan_type = L2CAP_CHAN_CONN_FIX_A2MP;
 	chan->flush_to = L2CAP_DEFAULT_FLUSH_TO;
 
 	chan->ops = &a2mp_chan_ops;
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index eb0ccef..621da9d 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -465,6 +465,13 @@ static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
 		chan->omtu = L2CAP_DEFAULT_MTU;
 		break;
 
+	case L2CAP_CHAN_CONN_FIX_A2MP:
+		chan->scid = L2CAP_CID_A2MP;
+		chan->dcid = L2CAP_CID_A2MP;
+		chan->omtu = L2CAP_A2MP_DEFAULT_MTU;
+		chan->imtu = L2CAP_A2MP_DEFAULT_MTU;
+		break;
+
 	default:
 		/* Raw socket can send/recv signalling messages only */
 		chan->scid = L2CAP_CID_SIGNALING;
@@ -1000,6 +1007,11 @@ static void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *c
 		__clear_ack_timer(chan);
 	}
 
+	if (chan->chan_type == L2CAP_CHAN_CONN_FIX_A2MP) {
+		__l2cap_state_change(chan, BT_DISCONN);
+		return;
+	}
+
 	req.dcid = cpu_to_le16(chan->dcid);
 	req.scid = cpu_to_le16(chan->scid);
 	l2cap_send_cmd(conn, l2cap_get_ident(conn),
@@ -1194,6 +1206,11 @@ static void l2cap_conn_ready(struct l2cap_conn *conn)
 
 		l2cap_chan_lock(chan);
 
+		if (chan->chan_type == L2CAP_CHAN_CONN_FIX_A2MP) {
+			l2cap_chan_unlock(chan);
+			continue;
+		}
+
 		if (conn->hcon->type == LE_LINK) {
 			if (smp_conn_security(conn, chan->sec_level))
 				l2cap_chan_ready(chan);
-- 
1.7.9.5


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

* [PATCHv4 17/17] Bluetooth: A2MP: Manage incoming connections
  2012-05-29 10:59 ` [PATCHv4 00/17] Bluetooth A2MP implementation Andrei Emeltchenko
                     ` (15 preceding siblings ...)
  2012-05-29 10:59   ` [PATCHv4 16/17] Bluetooth: A2MP: Handling fixed channels Andrei Emeltchenko
@ 2012-05-29 10:59   ` Andrei Emeltchenko
  2012-05-29 15:52     ` Gustavo Padovan
  16 siblings, 1 reply; 104+ messages in thread
From: Andrei Emeltchenko @ 2012-05-29 10:59 UTC (permalink / raw)
  To: linux-bluetooth

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

Handle incoming A2MP connection by creating AMP manager and
processing A2MP messages.

Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
 include/net/bluetooth/a2mp.h |    4 ++++
 net/bluetooth/a2mp.c         |   16 ++++++++++++++++
 net/bluetooth/l2cap_core.c   |   19 +++++++++++++++----
 3 files changed, 35 insertions(+), 4 deletions(-)

diff --git a/include/net/bluetooth/a2mp.h b/include/net/bluetooth/a2mp.h
index 96f9cc2..6a76e0a 100644
--- a/include/net/bluetooth/a2mp.h
+++ b/include/net/bluetooth/a2mp.h
@@ -15,6 +15,8 @@
 #ifndef __A2MP_H
 #define __A2MP_H
 
+#include <net/bluetooth/l2cap.h>
+
 #define A2MP_FEAT_EXT	0x8000
 
 struct amp_mgr {
@@ -118,5 +120,7 @@ struct a2mp_physlink_rsp {
 
 void amp_mgr_get(struct amp_mgr *mgr);
 int amp_mgr_put(struct amp_mgr *mgr);
+struct l2cap_chan *a2mp_channel_create(struct l2cap_conn *conn,
+				       struct sk_buff *skb);
 
 #endif /* __A2MP_H */
diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c
index 2019fe3..859a055 100644
--- a/net/bluetooth/a2mp.c
+++ b/net/bluetooth/a2mp.c
@@ -571,3 +571,19 @@ static struct amp_mgr *amp_mgr_create(struct l2cap_conn *conn)
 
 	return mgr;
 }
+
+struct l2cap_chan *a2mp_channel_create(struct l2cap_conn *conn,
+				       struct sk_buff *skb)
+{
+	struct amp_mgr *mgr;
+
+	mgr = amp_mgr_create(conn);
+	if (!mgr) {
+		BT_ERR("Could not create AMP manager");
+		return NULL;
+	}
+
+	BT_DBG("mgr: %p chan %p", mgr, mgr->a2mp_chan);
+
+	return mgr->a2mp_chan;
+}
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 621da9d..953ac53 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -37,6 +37,7 @@
 #include <net/bluetooth/hci_core.h>
 #include <net/bluetooth/l2cap.h>
 #include <net/bluetooth/smp.h>
+#include <net/bluetooth/a2mp.h>
 
 bool disable_ertm;
 
@@ -5131,10 +5132,20 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk
 
 	chan = l2cap_get_chan_by_scid(conn, cid);
 	if (!chan) {
-		BT_DBG("unknown cid 0x%4.4x", cid);
-		/* Drop packet and return */
-		kfree_skb(skb);
-		return 0;
+		if (cid == L2CAP_CID_A2MP) {
+			chan = a2mp_channel_create(conn, skb);
+			if (!chan) {
+				kfree_skb(skb);
+				return 0;
+			}
+
+			l2cap_chan_lock(chan);
+		} else {
+			BT_DBG("unknown cid 0x%4.4x", cid);
+			/* Drop packet and return */
+			kfree_skb(skb);
+			return 0;
+		}
 	}
 
 	BT_DBG("chan %p, len %d", chan, skb->len);
-- 
1.7.9.5


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

* Re: [PATCHv4 17/17] Bluetooth: A2MP: Manage incoming connections
  2012-05-29 10:59   ` [PATCHv4 17/17] Bluetooth: A2MP: Manage incoming connections Andrei Emeltchenko
@ 2012-05-29 15:52     ` Gustavo Padovan
  0 siblings, 0 replies; 104+ messages in thread
From: Gustavo Padovan @ 2012-05-29 15:52 UTC (permalink / raw)
  To: Andrei Emeltchenko; +Cc: linux-bluetooth

Hi Andrei,

* Andrei Emeltchenko <Andrei.Emeltchenko.news@gmail.com> [2012-05-29 13:59:17 +0300]:

> From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
> 
> Handle incoming A2MP connection by creating AMP manager and
> processing A2MP messages.
> 
> Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
> ---
>  include/net/bluetooth/a2mp.h |    4 ++++
>  net/bluetooth/a2mp.c         |   16 ++++++++++++++++
>  net/bluetooth/l2cap_core.c   |   19 +++++++++++++++----
>  3 files changed, 35 insertions(+), 4 deletions(-)

A 17 patches were applied to bluetooth-next. Thanks.

	Gustavo

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

* Re: [PATCHv1 01/17] Bluetooth: A2MP: Create A2MP channel
  2012-05-28 13:59                   ` Andrei Emeltchenko
@ 2012-05-29 16:23                     ` Mat Martineau
  2012-05-30 13:29                       ` Andrei Emeltchenko
  0 siblings, 1 reply; 104+ messages in thread
From: Mat Martineau @ 2012-05-29 16:23 UTC (permalink / raw)
  To: Andrei Emeltchenko; +Cc: linux-bluetooth, pkrystad, marcel


On Mon, 28 May 2012, Andrei Emeltchenko wrote:

> Hi Mat,
>
> On Mon, May 28, 2012 at 10:24:56AM +0300, Andrei Emeltchenko wrote:
>>>>> The risk is not memory leaks - if the other device closes the ACL,
>>>>> then the A2MP channel will be cleaned up.  But if you had two BlueZ
>>>>> devices with A2MP connected to each other, the ACL would never close
>>>>> as long as the devices remained powered and in range!  Nothing would
>>>>> trigger the flush as long as the hci_conn is held.
>>>>
>>>> Does it indicate that we have problem with rather freeing amp_mgr?
>>>
>>> It looks like the amp_mgr will be freed if the channel is closed.
>>> There's nothing that will close the channel except for:
>>>
>>> * Remote device disconnects the ACL
>>> * Remote device goes out of range
>>> * Local BR/EDR controller is powered down or reset
>>>
>>>>> I think the checks for hci_conn_put are necessary, even if they are
>>>>> ugly.
>>>>
>>>> I think that if I have hci_conn_hold when creating channel and
>>>> hci_conn_put when closing channel that does not differ from the case when
>>>> I do not have hci_conn_put/hold.
>>>
>>> If there was something that closed the A2MP channel, there would be
>>> no difference.  But nothing closes the A2MP channel.
>>
>> I actually was thinking about timers which could do clean up.
>>
>>>> So you are probably referring to the case when hci_conn needs to be closed
>>>> but cannot because it has hci_conn_hold in a2mp channel?
>>>
>>> Yes.
>>>
>>>> This also means that we still have L2CAP channel (a2mp) hanging.
>>>> This seems right to me if I did not miss something.
>>>
>>> Since A2MP is a fixed channel, it is not opened and closed like
>>> typical L2CAP channels.  Consider this scenario:
>>>
>>> 1. Remote device decides to connect
>>> 2. ACL is created
>>> 3. Remote device sends A2MP discover
>>> 4. A2MP channel is set up, AMP manager is created, hci_conn_hold for
>>> A2MP channel
>>> 5. Remote device connects L2CAP channel over BR/EDR.  hci_conn_hold
>>> for the data channel
>>> 6. A2MP communication to set up physical link
>>> 7. L2CAP channel move to AMP controller
>>> 8. Data sent over AMP.
>>> 9. L2CAP channel disconnected, hci_conn_put for the data channel
>>> 10. Device stays in range.  hci_conn reference count is not 0, so
>>> ACL is not closed.
>>
>> My concern here if A2MP does not reference hci_conn can hci_conn be
>> removed while we still have A2MP chan in some situation?

hci_conn_hold and hci_conn_put are not reference counts on the 
hci_conn structure in the typical way.  They are reference counts for 
the ACL.  When you do the last hci_conn_put, the ACL is disconnected 
after a timeout.

With or without hci_conn_hold for the A2MP channel, the ACL can 
disappear at any time.  The AMP manager must deal with that without 
crashing like it does in your trace.

> I just tested code with PTS and got one crash:
>
> <------8<--------------------------------------------------------------------
> |  [  275.100760] [5] hci_chan_del: hci0 conn f3ff0800 chan e818e540
> |  [  275.109610] [19] l2cap_send_rr_or_rnr: chan e806b800, poll 0
> |  [  275.127922] [19] l2cap_send_sframe: chan e806b800, control f5ef3ed8
> |  [  275.133532] [19] l2cap_send_sframe: reqseq 2, final 0, poll 0, super 0
> |  [  275.173033] [5] hci_conn_del: hci0 conn f3ff0800 handle 11
> |  [  275.181131] [5] hci_chan_list_flush: conn f3ff0800
> |  [  275.202645] [5] amp_mgr_put: mgr e8260600
> <------8<--------------------------------------------------------------------
>
> Here we deleted the last L2CAP channel

Ok.  The AMP manager should not attempt to send anything after this.

>
> <------8<------------------------------------------------------------------
> |  [  275.295020] BUG: unable to handle kernel NULL pointer dereference at
> |  (null)
> |  [  275.298791] IP: [<f8362e6c>] l2cap_do_send+0x1c/0xa0 [bluetooth]
> |  [  275.298791] *pde = 00000000
> |  [  275.298791] Oops: 0000 [#1] SMP
> <------8<------------------------------------------------------------------
>
> Then we got the crash probably hci_conn deleted faster then we get reply
> from AMP controller

This looks like a crash when the AMP manager tries to send something. 
It should not be trying to send anything at this point.

Once the AMP manager gets a state change callback with BT_CLOSED or a 
a close callback, amp_mgr->l2cap_conn and amp_mgr->a2mp_chan are 
invalid - even if the AMP manager has not been freed.

>
> <------8<---------------------------------------------------------------------
> |  [  275.298791] EIP: [<f8362e6c>] l2cap_do_send+0x1c/0xa0 [bluetooth]
> |  SS:ESP 0068:f5ef3e58
> |  [  275.298791] CR2: 0000000000000000
> |  [  276.553113] Bluetooth: hci1 command tx timeout
> |  [  276.553706] ---[ end trace b08f23ddb2b49a2e ]---
> |  [  276.577494] [30] hci_queue_cb: Queue cmd ed3d5540 opt e8260600
> |  [  276.723885] [30] l2cap_segment_sdu: chan e806b800, msg f5919e94, len 22
> |  [  276.790990] BUG: unable to handle kernel NULL pointer dereference at
> |  00000010
> |  [  276.794865] IP: [<f83694dd>] l2cap_chan_send+0x28d/0xb40 [bluetooth]
> <------8<---------------------------------------------------------------------


Regards,

--
Mat Martineau
Employee of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum


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

* Re: [PATCHv1 01/17] Bluetooth: A2MP: Create A2MP channel
  2012-05-29 16:23                     ` Mat Martineau
@ 2012-05-30 13:29                       ` Andrei Emeltchenko
  0 siblings, 0 replies; 104+ messages in thread
From: Andrei Emeltchenko @ 2012-05-30 13:29 UTC (permalink / raw)
  To: Mat Martineau; +Cc: linux-bluetooth, pkrystad, marcel

Hi Mat,

On Tue, May 29, 2012 at 09:23:34AM -0700, Mat Martineau wrote:
> >>>Since A2MP is a fixed channel, it is not opened and closed like
> >>>typical L2CAP channels.  Consider this scenario:
> >>>
> >>>1. Remote device decides to connect
> >>>2. ACL is created
> >>>3. Remote device sends A2MP discover
> >>>4. A2MP channel is set up, AMP manager is created, hci_conn_hold for
> >>>A2MP channel
> >>>5. Remote device connects L2CAP channel over BR/EDR.  hci_conn_hold
> >>>for the data channel
> >>>6. A2MP communication to set up physical link
> >>>7. L2CAP channel move to AMP controller
> >>>8. Data sent over AMP.
> >>>9. L2CAP channel disconnected, hci_conn_put for the data channel
> >>>10. Device stays in range.  hci_conn reference count is not 0, so
> >>>ACL is not closed.
> >>
> >>My concern here if A2MP does not reference hci_conn can hci_conn be
> >>removed while we still have A2MP chan in some situation?
> 
> hci_conn_hold and hci_conn_put are not reference counts on the
> hci_conn structure in the typical way.  They are reference counts
> for the ACL.  When you do the last hci_conn_put, the ACL is
> disconnected after a timeout.
> 
> With or without hci_conn_hold for the A2MP channel, the ACL can
> disappear at any time.  The AMP manager must deal with that without
> crashing like it does in your trace.

OK, I found the bug, solution would be to define teardown for a2mp channel
to make sure all callbacks are cleared.

-static void a2mp_chan_no_teardown_cb(struct l2cap_chan *chan, int err)
+static void a2mp_chan_teardown_cb(struct l2cap_chan *chan, int err)
 {
-       BT_ERR("teardown for chan %p not implemented", chan);
+       struct hci_dev *hdev;
+
+       BT_DBG("chan %p", chan);
+
+       read_lock(&hci_dev_list_lock);
+       list_for_each_entry(hdev, &hci_dev_list, list) {
+               /* Iterate through AMP controllers */
+               if (hdev->amp_type == HCI_AMP)
+                       hci_cb_clear(hdev);
+       }
+       read_unlock(&hci_dev_list_lock);
 }

> >I just tested code with PTS and got one crash:
> >
> ><------8<--------------------------------------------------------------------
> >|  [  275.100760] [5] hci_chan_del: hci0 conn f3ff0800 chan e818e540
> >|  [  275.109610] [19] l2cap_send_rr_or_rnr: chan e806b800, poll 0
> >|  [  275.127922] [19] l2cap_send_sframe: chan e806b800, control f5ef3ed8
> >|  [  275.133532] [19] l2cap_send_sframe: reqseq 2, final 0, poll 0, super 0
> >|  [  275.173033] [5] hci_conn_del: hci0 conn f3ff0800 handle 11
> >|  [  275.181131] [5] hci_chan_list_flush: conn f3ff0800
> >|  [  275.202645] [5] amp_mgr_put: mgr e8260600
> ><------8<--------------------------------------------------------------------
> >
> >Here we deleted the last L2CAP channel
> 
> Ok.  The AMP manager should not attempt to send anything after this.
> 
> >
> ><------8<------------------------------------------------------------------
> >|  [  275.295020] BUG: unable to handle kernel NULL pointer dereference at
> >|  (null)
> >|  [  275.298791] IP: [<f8362e6c>] l2cap_do_send+0x1c/0xa0 [bluetooth]
> >|  [  275.298791] *pde = 00000000
> >|  [  275.298791] Oops: 0000 [#1] SMP
> ><------8<------------------------------------------------------------------
> >
> >Then we got the crash probably hci_conn deleted faster then we get reply
> >from AMP controller
> 
> This looks like a crash when the AMP manager tries to send
> something. It should not be trying to send anything at this point.
> 
> Once the AMP manager gets a state change callback with BT_CLOSED or
> a a close callback, amp_mgr->l2cap_conn and amp_mgr->a2mp_chan are
> invalid - even if the AMP manager has not been freed.

Sometimes we do not get this state change for a2mp channel.

Best regards 
Andrei Emeltchenko 

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

end of thread, other threads:[~2012-05-30 13:29 UTC | newest]

Thread overview: 104+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-05-18 14:25 [PATCHv1 00/17] Bluetooth A2MP implementation Andrei Emeltchenko
2012-05-18 14:25 ` [PATCHv1 01/17] Bluetooth: A2MP: Create A2MP channel Andrei Emeltchenko
2012-05-22 17:45   ` Mat Martineau
2012-05-23  7:49     ` Andrei Emeltchenko
2012-05-23 15:44       ` Mat Martineau
2012-05-24  7:51         ` Andrei Emeltchenko
2012-05-24 15:59           ` Mat Martineau
2012-05-25  8:09             ` Andrei Emeltchenko
2012-05-25 17:18               ` Mat Martineau
2012-05-28  7:24                 ` Andrei Emeltchenko
2012-05-28 13:59                   ` Andrei Emeltchenko
2012-05-29 16:23                     ` Mat Martineau
2012-05-30 13:29                       ` Andrei Emeltchenko
2012-05-18 14:25 ` [PATCHv1 02/17] Bluetooth: A2MP: AMP Manager basic functions Andrei Emeltchenko
2012-05-18 14:25 ` [PATCHv1 03/17] Bluetooth: A2MP: Build and Send msg helpers Andrei Emeltchenko
2012-05-18 14:25 ` [PATCHv1 04/17] Bluetooth: A2MP: Add chan callbacks Andrei Emeltchenko
2012-05-18 14:25 ` [PATCHv1 05/17] Bluetooth: A2MP: Definitions for A2MP commands Andrei Emeltchenko
2012-05-18 14:25 ` [PATCHv1 06/17] Bluetooth: A2MP: Define A2MP status codes Andrei Emeltchenko
2012-05-18 14:25 ` [PATCHv1 07/17] Bluetooth: A2MP: Process A2MP messages Andrei Emeltchenko
2012-05-18 14:25 ` [PATCHv1 08/17] Bluetooth: A2MP: Process A2MP Command Reject Andrei Emeltchenko
2012-05-18 14:25 ` [PATCHv1 09/17] Bluetooth: A2MP: Process A2MP Discover Request Andrei Emeltchenko
2012-05-18 14:25 ` [PATCHv1 10/17] Bluetooth: A2MP: Process A2MP Change Notify Andrei Emeltchenko
2012-05-18 14:25 ` [PATCHv1 11/17] Bluetooth: A2MP: Process A2MP Get Info Request Andrei Emeltchenko
2012-05-18 14:25 ` [PATCHv1 12/17] Bluetooth: A2MP: Process A2MP Get AMP Assoc Request Andrei Emeltchenko
2012-05-18 14:25 ` [PATCHv1 13/17] Bluetooth: A2MP: Process A2MP Create Physlink Request Andrei Emeltchenko
2012-05-18 14:25 ` [PATCHv1 14/17] Bluetooth: A2MP: Process A2MP Disc " Andrei Emeltchenko
2012-05-18 14:25 ` [PATCHv1 15/17] Bluetooth: A2MP: Process A2MP Command Responses Andrei Emeltchenko
2012-05-18 14:25 ` [PATCHv1 16/17] Bluetooth: A2MP: Handling fixed channels Andrei Emeltchenko
2012-05-21 22:28   ` Mat Martineau
2012-05-22  8:12     ` Andrei Emeltchenko
2012-05-22 17:35       ` Mat Martineau
2012-05-18 14:25 ` [PATCHv1 17/17] Bluetooth: A2MP: Manage incoming connections Andrei Emeltchenko
2012-05-21 22:45   ` Mat Martineau
2012-05-22  7:37     ` Andrei Emeltchenko
2012-05-22 17:38       ` Mat Martineau
2012-05-18 20:57 ` [PATCHv1 00/17] Bluetooth A2MP implementation Gustavo Padovan
2012-05-23 15:37 ` [PATCHv2 00/19] " Andrei Emeltchenko
2012-05-23 15:37   ` [PATCHv2 01/19] Bluetooth: Add unlink to L2CAP channel ops Andrei Emeltchenko
2012-05-23 23:13     ` Mat Martineau
2012-05-23 15:37   ` [PATCHv2 02/19] Bluetooth: Add ready " Andrei Emeltchenko
2012-05-23 23:16     ` Mat Martineau
2012-05-24  7:59       ` Andrei Emeltchenko
2012-05-23 15:37   ` [PATCHv2 03/19] Bluetooth: A2MP: Create A2MP channel Andrei Emeltchenko
2012-05-23 15:37   ` [PATCHv2 04/19] Bluetooth: A2MP: AMP Manager basic functions Andrei Emeltchenko
2012-05-23 15:37   ` [PATCHv2 05/19] Bluetooth: A2MP: Build and Send msg helpers Andrei Emeltchenko
2012-05-23 15:37   ` [PATCHv2 06/19] Bluetooth: A2MP: Add chan callbacks Andrei Emeltchenko
2012-05-23 15:37   ` [PATCHv2 07/19] Bluetooth: A2MP: Definitions for A2MP commands Andrei Emeltchenko
2012-05-23 15:37   ` [PATCHv2 08/19] Bluetooth: A2MP: Define A2MP status codes Andrei Emeltchenko
2012-05-23 15:37   ` [PATCHv2 09/19] Bluetooth: A2MP: Process A2MP messages Andrei Emeltchenko
2012-05-23 15:37   ` [PATCHv2 10/19] Bluetooth: A2MP: Process A2MP Command Reject Andrei Emeltchenko
2012-05-23 15:37   ` [PATCHv2 11/19] Bluetooth: A2MP: Process A2MP Discover Request Andrei Emeltchenko
2012-05-23 15:37   ` [PATCHv2 12/19] Bluetooth: A2MP: Process A2MP Change Notify Andrei Emeltchenko
2012-05-23 15:37   ` [PATCHv2 13/19] Bluetooth: A2MP: Process A2MP Get Info Request Andrei Emeltchenko
2012-05-23 15:37   ` [PATCHv2 14/19] Bluetooth: A2MP: Process A2MP Get AMP Assoc Request Andrei Emeltchenko
2012-05-23 15:37   ` [PATCHv2 15/19] Bluetooth: A2MP: Process A2MP Create Physlink Request Andrei Emeltchenko
2012-05-23 15:37   ` [PATCHv2 16/19] Bluetooth: A2MP: Process A2MP Disc " Andrei Emeltchenko
2012-05-23 15:37   ` [PATCHv2 17/19] Bluetooth: A2MP: Process A2MP Command Responses Andrei Emeltchenko
2012-05-23 15:37   ` [PATCHv2 18/19] Bluetooth: A2MP: Handling fixed channels Andrei Emeltchenko
2012-05-23 15:37   ` [PATCHv2 19/19] Bluetooth: A2MP: Manage incoming connections Andrei Emeltchenko
2012-05-23 23:30     ` Mat Martineau
2012-05-24 11:43       ` Andrei Emeltchenko
2012-05-24 11:38 ` [PATCHv3 00/18] Bluetooth A2MP implementation Andrei Emeltchenko
2012-05-24 11:38   ` [PATCHv3 01/18] Bluetooth: Add ready to L2CAP channel ops Andrei Emeltchenko
2012-05-24 11:38   ` [PATCHv3 02/18] Bluetooth: A2MP: Create A2MP channel Andrei Emeltchenko
2012-05-24 11:38   ` [PATCHv3 03/18] Bluetooth: A2MP: AMP Manager basic functions Andrei Emeltchenko
2012-05-24 11:38   ` [PATCHv3 04/18] Bluetooth: A2MP: Build and Send msg helpers Andrei Emeltchenko
2012-05-24 11:38   ` [PATCHv3 05/18] Bluetooth: A2MP: Add chan callbacks Andrei Emeltchenko
2012-05-25 12:20     ` Gustavo Padovan
2012-05-25 13:08       ` Andrei Emeltchenko
2012-05-24 11:38   ` [PATCHv3 06/18] Bluetooth: A2MP: Definitions for A2MP commands Andrei Emeltchenko
2012-05-24 11:38   ` [PATCHv3 07/18] Bluetooth: A2MP: Define A2MP status codes Andrei Emeltchenko
2012-05-24 11:38   ` [PATCHv3 08/18] Bluetooth: A2MP: Process A2MP messages Andrei Emeltchenko
2012-05-24 11:38   ` [PATCHv3 09/18] Bluetooth: A2MP: Process A2MP Command Reject Andrei Emeltchenko
2012-05-24 11:38   ` [PATCHv3 10/18] Bluetooth: A2MP: Process A2MP Discover Request Andrei Emeltchenko
2012-05-25 12:19     ` Gustavo Padovan
2012-05-25 13:11       ` Andrei Emeltchenko
2012-05-24 11:38   ` [PATCHv3 11/18] Bluetooth: A2MP: Process A2MP Change Notify Andrei Emeltchenko
2012-05-25 12:29     ` Gustavo Padovan
2012-05-24 11:38   ` [PATCHv3 12/18] Bluetooth: A2MP: Process A2MP Get Info Request Andrei Emeltchenko
2012-05-24 11:38   ` [PATCHv3 13/18] Bluetooth: A2MP: Process A2MP Get AMP Assoc Request Andrei Emeltchenko
2012-05-24 11:38   ` [PATCHv3 14/18] Bluetooth: A2MP: Process A2MP Create Physlink Request Andrei Emeltchenko
2012-05-24 11:38   ` [PATCHv3 15/18] Bluetooth: A2MP: Process A2MP Disc " Andrei Emeltchenko
2012-05-24 11:38   ` [PATCHv3 16/18] Bluetooth: A2MP: Process A2MP Command Responses Andrei Emeltchenko
2012-05-24 11:38   ` [PATCHv3 17/18] Bluetooth: A2MP: Handling fixed channels Andrei Emeltchenko
2012-05-24 11:38   ` [PATCHv3 18/18] Bluetooth: A2MP: Manage incoming connections Andrei Emeltchenko
2012-05-29 10:59 ` [PATCHv4 00/17] Bluetooth A2MP implementation Andrei Emeltchenko
2012-05-29 10:59   ` [PATCHv4 01/17] Bluetooth: A2MP: Create A2MP channel Andrei Emeltchenko
2012-05-29 10:59   ` [PATCHv4 02/17] Bluetooth: A2MP: AMP Manager basic functions Andrei Emeltchenko
2012-05-29 10:59   ` [PATCHv4 03/17] Bluetooth: A2MP: Build and Send msg helpers Andrei Emeltchenko
2012-05-29 10:59   ` [PATCHv4 04/17] Bluetooth: A2MP: Add chan callbacks Andrei Emeltchenko
2012-05-29 10:59   ` [PATCHv4 05/17] Bluetooth: A2MP: Definitions for A2MP commands Andrei Emeltchenko
2012-05-29 10:59   ` [PATCHv4 06/17] Bluetooth: A2MP: Define A2MP status codes Andrei Emeltchenko
2012-05-29 10:59   ` [PATCHv4 07/17] Bluetooth: A2MP: Process A2MP messages Andrei Emeltchenko
2012-05-29 10:59   ` [PATCHv4 08/17] Bluetooth: A2MP: Process A2MP Command Reject Andrei Emeltchenko
2012-05-29 10:59   ` [PATCHv4 09/17] Bluetooth: A2MP: Process A2MP Discover Request Andrei Emeltchenko
2012-05-29 10:59   ` [PATCHv4 10/17] Bluetooth: A2MP: Process A2MP Change Notify Andrei Emeltchenko
2012-05-29 10:59   ` [PATCHv4 11/17] Bluetooth: A2MP: Process A2MP Get Info Request Andrei Emeltchenko
2012-05-29 10:59   ` [PATCHv4 12/17] Bluetooth: A2MP: Process A2MP Get AMP Assoc Request Andrei Emeltchenko
2012-05-29 10:59   ` [PATCHv4 13/17] Bluetooth: A2MP: Process A2MP Create Physlink Request Andrei Emeltchenko
2012-05-29 10:59   ` [PATCHv4 14/17] Bluetooth: A2MP: Process A2MP Disc " Andrei Emeltchenko
2012-05-29 10:59   ` [PATCHv4 15/17] Bluetooth: A2MP: Process A2MP Command Responses Andrei Emeltchenko
2012-05-29 10:59   ` [PATCHv4 16/17] Bluetooth: A2MP: Handling fixed channels Andrei Emeltchenko
2012-05-29 10:59   ` [PATCHv4 17/17] Bluetooth: A2MP: Manage incoming connections Andrei Emeltchenko
2012-05-29 15:52     ` Gustavo Padovan

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.