Linux bluetooth development
 help / color / mirror / Atom feed
* [PATCH 2/5 v2] Bluetooth: Fix LE MTU reporting for HCIGETDEVINFO
From: Johan Hedberg @ 2012-10-19 17:57 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1350669469-7719-1-git-send-email-johan.hedberg@gmail.com>

From: Johan Hedberg <johan.hedberg@intel.com>

This patch fixes the use of le_mtu and le_pkts values in the
HCIGETDEVINFO ioctl for LE-only controllers.

Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
---
 net/bluetooth/hci_core.c |   15 +++++++++++----
 1 file changed, 11 insertions(+), 4 deletions(-)

diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index dd05ed0..487308b 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -990,10 +990,17 @@ int hci_get_dev_info(void __user *arg)
 	di.type     = (hdev->bus & 0x0f) | (hdev->dev_type << 4);
 	di.flags    = hdev->flags;
 	di.pkt_type = hdev->pkt_type;
-	di.acl_mtu  = hdev->acl_mtu;
-	di.acl_pkts = hdev->acl_pkts;
-	di.sco_mtu  = hdev->sco_mtu;
-	di.sco_pkts = hdev->sco_pkts;
+	if (lmp_bredr_capable(hdev)) {
+		di.acl_mtu  = hdev->acl_mtu;
+		di.acl_pkts = hdev->acl_pkts;
+		di.sco_mtu  = hdev->sco_mtu;
+		di.sco_pkts = hdev->sco_pkts;
+	} else {
+		di.acl_mtu  = hdev->le_mtu;
+		di.acl_pkts = hdev->le_pkts;
+		di.sco_mtu  = 0;
+		di.sco_pkts = 0;
+	}
 	di.link_policy = hdev->link_policy;
 	di.link_mode   = hdev->link_mode;
 
-- 
1.7.10.4


^ permalink raw reply related

* [PATCH 1/5 v2] Bluetooth: Add initial support for LE-only controllers
From: Johan Hedberg @ 2012-10-19 17:57 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1350669469-7719-1-git-send-email-johan.hedberg@gmail.com>

From: Johan Hedberg <johan.hedberg@intel.com>

This patch splits off most the HCI init sequence commands from a fixed
set into a conditional one that is sent once the HCI_Read_Local_Features
and HCI_Read_Local_Version_Information commands complete. This is
necessary since many of the current fixed commands are not allowed for
LE-only controllers.

Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
---
 net/bluetooth/hci_core.c  |   47 ------------------------------------
 net/bluetooth/hci_event.c |   58 +++++++++++++++++++++++++++++++++++++++++----
 2 files changed, 53 insertions(+), 52 deletions(-)

diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 0ec776a..dd05ed0 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -178,48 +178,13 @@ static void hci_reset_req(struct hci_dev *hdev, unsigned long opt)
 
 static void bredr_init(struct hci_dev *hdev)
 {
-	struct hci_cp_delete_stored_link_key cp;
-	__le16 param;
-	__u8 flt_type;
-
 	hdev->flow_ctl_mode = HCI_FLOW_CTL_MODE_PACKET_BASED;
 
-	/* Mandatory initialization */
-
 	/* Read Local Supported Features */
 	hci_send_cmd(hdev, HCI_OP_READ_LOCAL_FEATURES, 0, NULL);
 
 	/* Read Local Version */
 	hci_send_cmd(hdev, HCI_OP_READ_LOCAL_VERSION, 0, NULL);
-
-	/* Read Buffer Size (ACL mtu, max pkt, etc.) */
-	hci_send_cmd(hdev, HCI_OP_READ_BUFFER_SIZE, 0, NULL);
-
-	/* Read BD Address */
-	hci_send_cmd(hdev, HCI_OP_READ_BD_ADDR, 0, NULL);
-
-	/* Read Class of Device */
-	hci_send_cmd(hdev, HCI_OP_READ_CLASS_OF_DEV, 0, NULL);
-
-	/* Read Local Name */
-	hci_send_cmd(hdev, HCI_OP_READ_LOCAL_NAME, 0, NULL);
-
-	/* Read Voice Setting */
-	hci_send_cmd(hdev, HCI_OP_READ_VOICE_SETTING, 0, NULL);
-
-	/* Optional initialization */
-
-	/* Clear Event Filters */
-	flt_type = HCI_FLT_CLEAR_ALL;
-	hci_send_cmd(hdev, HCI_OP_SET_EVENT_FLT, 1, &flt_type);
-
-	/* Connection accept timeout ~20 secs */
-	param = __constant_cpu_to_le16(0x7d00);
-	hci_send_cmd(hdev, HCI_OP_WRITE_CA_TIMEOUT, 2, &param);
-
-	bacpy(&cp.bdaddr, BDADDR_ANY);
-	cp.delete_all = 1;
-	hci_send_cmd(hdev, HCI_OP_DELETE_STORED_LINK_KEY, sizeof(cp), &cp);
 }
 
 static void amp_init(struct hci_dev *hdev)
@@ -273,14 +238,6 @@ static void hci_init_req(struct hci_dev *hdev, unsigned long opt)
 	}
 }
 
-static void hci_le_init_req(struct hci_dev *hdev, unsigned long opt)
-{
-	BT_DBG("%s", hdev->name);
-
-	/* Read LE buffer size */
-	hci_send_cmd(hdev, HCI_OP_LE_READ_BUFFER_SIZE, 0, NULL);
-}
-
 static void hci_scan_req(struct hci_dev *hdev, unsigned long opt)
 {
 	__u8 scan = opt;
@@ -687,10 +644,6 @@ int hci_dev_open(__u16 dev)
 
 		ret = __hci_request(hdev, hci_init_req, 0, HCI_INIT_TIMEOUT);
 
-		if (lmp_host_le_capable(hdev))
-			ret = __hci_request(hdev, hci_le_init_req, 0,
-					    HCI_INIT_TIMEOUT);
-
 		clear_bit(HCI_INIT, &hdev->flags);
 	}
 
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 0383635..f4f0b8b 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -507,11 +507,13 @@ static void hci_setup_event_mask(struct hci_dev *hdev)
 	if (hdev->hci_ver < BLUETOOTH_VER_1_2)
 		return;
 
-	events[4] |= 0x01; /* Flow Specification Complete */
-	events[4] |= 0x02; /* Inquiry Result with RSSI */
-	events[4] |= 0x04; /* Read Remote Extended Features Complete */
-	events[5] |= 0x08; /* Synchronous Connection Complete */
-	events[5] |= 0x10; /* Synchronous Connection Changed */
+	if (lmp_bredr_capable(hdev)) {
+		events[4] |= 0x01; /* Flow Specification Complete */
+		events[4] |= 0x02; /* Inquiry Result with RSSI */
+		events[4] |= 0x04; /* Read Remote Extended Features Complete */
+		events[5] |= 0x08; /* Synchronous Connection Complete */
+		events[5] |= 0x10; /* Synchronous Connection Changed */
+	}
 
 	if (hdev->features[3] & LMP_RSSI_INQ)
 		events[4] |= 0x02; /* Inquiry Result with RSSI */
@@ -550,11 +552,57 @@ static void hci_setup_event_mask(struct hci_dev *hdev)
 	hci_send_cmd(hdev, HCI_OP_SET_EVENT_MASK, sizeof(events), events);
 }
 
+static void bredr_init(struct hci_dev *hdev)
+{
+	struct hci_cp_delete_stored_link_key cp;
+	__le16 param;
+	__u8 flt_type;
+
+	/* Read Buffer Size (ACL mtu, max pkt, etc.) */
+	hci_send_cmd(hdev, HCI_OP_READ_BUFFER_SIZE, 0, NULL);
+
+	/* Read Class of Device */
+	hci_send_cmd(hdev, HCI_OP_READ_CLASS_OF_DEV, 0, NULL);
+
+	/* Read Local Name */
+	hci_send_cmd(hdev, HCI_OP_READ_LOCAL_NAME, 0, NULL);
+
+	/* Read Voice Setting */
+	hci_send_cmd(hdev, HCI_OP_READ_VOICE_SETTING, 0, NULL);
+
+	/* Clear Event Filters */
+	flt_type = HCI_FLT_CLEAR_ALL;
+	hci_send_cmd(hdev, HCI_OP_SET_EVENT_FLT, 1, &flt_type);
+
+	/* Connection accept timeout ~20 secs */
+	param = __constant_cpu_to_le16(0x7d00);
+	hci_send_cmd(hdev, HCI_OP_WRITE_CA_TIMEOUT, 2, &param);
+
+	bacpy(&cp.bdaddr, BDADDR_ANY);
+	cp.delete_all = 1;
+	hci_send_cmd(hdev, HCI_OP_DELETE_STORED_LINK_KEY, sizeof(cp), &cp);
+}
+
+static void le_init(struct hci_dev *hdev)
+{
+	/* Read LE Buffer Size */
+	hci_send_cmd(hdev, HCI_OP_LE_READ_BUFFER_SIZE, 0, NULL);
+}
+
 static void hci_setup(struct hci_dev *hdev)
 {
 	if (hdev->dev_type != HCI_BREDR)
 		return;
 
+	/* Read BD Address */
+	hci_send_cmd(hdev, HCI_OP_READ_BD_ADDR, 0, NULL);
+
+	if (lmp_bredr_capable(hdev))
+		bredr_init(hdev);
+
+	if (lmp_le_capable(hdev))
+		le_init(hdev);
+
 	hci_setup_event_mask(hdev);
 
 	if (hdev->hci_ver > BLUETOOTH_VER_1_1)
-- 
1.7.10.4


^ permalink raw reply related

* [PATCH 0/5 v2] Bluetooth: Add basic support for single-mode controllers
From: Johan Hedberg @ 2012-10-19 17:57 UTC (permalink / raw)
  To: linux-bluetooth

Hi,

Here's an update to the initial set with Marcel's comments taken into
account.

Johan


^ permalink raw reply

* Re: [PATCH 0/5 v2] Bluetooth: Add basic support for single-mode controllers
From: Marcel Holtmann @ 2012-10-19 17:57 UTC (permalink / raw)
  To: Johan Hedberg; +Cc: linux-bluetooth
In-Reply-To: <1350669469-7719-1-git-send-email-johan.hedberg@gmail.com>

Hi Johan,

> Here's an update to the initial set with Marcel's comments taken into
> account.

looks all good.

Acked-by: Marcel Holtmann <marcel@holtmann.org>

Regards

Marcel



^ permalink raw reply

* Re: [PATCH 6/6] Bluetooth: Read adversiting channel TX power during init sequence
From: Marcel Holtmann @ 2012-10-19 17:25 UTC (permalink / raw)
  To: Johan Hedberg; +Cc: linux-bluetooth
In-Reply-To: <1350666911-6334-7-git-send-email-johan.hedberg@gmail.com>

Hi Johan,

> This patch adds the reading of the LE advertising channel TX power to
> the HCI init sequence of LE-capable controllers. This data will be used
> e.g. for inclusion in the advertising data packets when advertising is
> enabled.
> 
> Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
> ---
>  include/net/bluetooth/hci.h      |    6 ++++++
>  include/net/bluetooth/hci_core.h |    2 ++
>  net/bluetooth/hci_event.c        |   20 ++++++++++++++++++++
>  3 files changed, 28 insertions(+)

Acked-by: Marcel Holtmann <marcel@holtmann.org>

Regards

Marcel



^ permalink raw reply

* Re: [PATCH 5/6] Bluetooth: Fix HCI command sending when powering on LE-only adapters
From: Marcel Holtmann @ 2012-10-19 17:24 UTC (permalink / raw)
  To: Johan Hedberg; +Cc: linux-bluetooth
In-Reply-To: <1350666911-6334-6-git-send-email-johan.hedberg@gmail.com>

Hi Johan,

> This patch makes sure that we don't send BR/EDR-only commands for
> LE-only adapters when they get powered on. Doing this would just cause
> command errors.
> 
> Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
> ---
>  net/bluetooth/mgmt.c |   34 +++++++++++++++++++++-------------
>  1 file changed, 21 insertions(+), 13 deletions(-)

Acked-by: Marcel Holtmann <marcel@holtmann.org>

Regards

Marcel



^ permalink raw reply

* Re: [PATCH 4/6] Bluetooth: Add setting of the LE event mask
From: Marcel Holtmann @ 2012-10-19 17:23 UTC (permalink / raw)
  To: Johan Hedberg; +Cc: linux-bluetooth
In-Reply-To: <1350666911-6334-5-git-send-email-johan.hedberg@gmail.com>

Hi Johan,

> This patch adds setting of the LE event mask to the HCI init procedure
> for LE-capable controllers. Right now we only set the default mask which
> is good enough for the events available in the 4.0 core specification.
> 
> Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
> ---
>  net/bluetooth/hci_event.c |   20 ++++++++++++++++++++
>  1 file changed, 20 insertions(+)

Acked-by: Marcel Holtmann <marcel@holtmann.org>

Regards

Marcel



^ permalink raw reply

* Re: [PATCH 3/6] Bluetooth: Add initial support for LE-only controllers
From: Marcel Holtmann @ 2012-10-19 17:23 UTC (permalink / raw)
  To: Johan Hedberg; +Cc: linux-bluetooth
In-Reply-To: <1350666911-6334-4-git-send-email-johan.hedberg@gmail.com>

Hi Johan,

> This patch splits off most the HCI init sequence commands from a fixed
> set into a conditional one that is sent once the HCI_Read_Local_Features
> command completes. This is necessary since many of the current fixed
> commands are not allowed for LE-only controllers.
> 
> Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
> ---
>  net/bluetooth/hci_core.c  |   35 ---------------------------
>  net/bluetooth/hci_event.c |   58 +++++++++++++++++++++++++++++++++++++++++----
>  2 files changed, 53 insertions(+), 40 deletions(-)

I would merge this one with patch 1/6. Having them split up seems a bit
weird. Especially with 2/6 in between that has nothing to do with it.

Regards

Marcel



^ permalink raw reply

* Re: [PATCH 2/6] Bluetooth: Fix LE MTU reporting for HCIGETDEVINFO
From: Marcel Holtmann @ 2012-10-19 17:20 UTC (permalink / raw)
  To: Johan Hedberg; +Cc: linux-bluetooth
In-Reply-To: <1350666911-6334-3-git-send-email-johan.hedberg@gmail.com>

Hi Johan,

> This patch fixes the use of le_mtu and le_pkts values in the
> HCIGETDEVINFO ioctl for LE-only controllers.
> 
> Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
> ---
>  net/bluetooth/hci_core.c |    9 +++++++--
>  1 file changed, 7 insertions(+), 2 deletions(-)
> 
> diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
> index 23359ef..b5a2be2 100644
> --- a/net/bluetooth/hci_core.c
> +++ b/net/bluetooth/hci_core.c
> @@ -1025,8 +1025,13 @@ int hci_get_dev_info(void __user *arg)
>  	di.type     = (hdev->bus & 0x0f) | (hdev->dev_type << 4);
>  	di.flags    = hdev->flags;
>  	di.pkt_type = hdev->pkt_type;
> -	di.acl_mtu  = hdev->acl_mtu;
> -	di.acl_pkts = hdev->acl_pkts;
> +	if (lmp_bredr_capable(hdev)) {
> +		di.acl_mtu  = hdev->acl_mtu;
> +		di.acl_pkts = hdev->acl_pkts;
> +	} else {
> +		di.acl_mtu  = hdev->le_mtu;
> +		di.acl_pkts = hdev->le_pkts;
> +	}
>  	di.sco_mtu  = hdev->sco_mtu;
>  	di.sco_pkts = hdev->sco_pkts;
>  	di.link_policy = hdev->link_policy;

shouldn't we ensure that di.sco_mtu and di.sco_pkts is set to 0 for LE
only devices. I rather make this explicit here instead of relying that
it is zeroed at controller creation. In theory there still is a code
path that might set these.

Regards

Marcel



^ permalink raw reply

* Re: [PATCH] Bluetooth: Fix having bogus entries in mgmt_read_index_list reply
From: Marcel Holtmann @ 2012-10-19 17:17 UTC (permalink / raw)
  To: Johan Hedberg; +Cc: linux-bluetooth
In-Reply-To: <1350666646-6276-1-git-send-email-johan.hedberg@gmail.com>

Hi Johan,

> The mgmt_read_index_list uses one loop to calculate the max needed size
> of its response with the help of an upper-bound of the controller count.
> The second loop is more strict as it checks for HCI_SETUP (which might
> have gotten set after the first loop) and could result in some indexes
> being skipped. Because of this the function needs to readjust the event
> length and index count after filling in the response array.
> 
> Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
> Cc: stable@vger.kernel.org
> ---
>  net/bluetooth/mgmt.c |   11 ++++++-----
>  1 file changed, 6 insertions(+), 5 deletions(-)

Acked-by: Marcel Holtmann <marcel@holtmann.org>

Regards

Marcel



^ permalink raw reply

* [PATCH 6/6] Bluetooth: Read adversiting channel TX power during init sequence
From: Johan Hedberg @ 2012-10-19 17:15 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1350666911-6334-1-git-send-email-johan.hedberg@gmail.com>

From: Johan Hedberg <johan.hedberg@intel.com>

This patch adds the reading of the LE advertising channel TX power to
the HCI init sequence of LE-capable controllers. This data will be used
e.g. for inclusion in the advertising data packets when advertising is
enabled.

Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
---
 include/net/bluetooth/hci.h      |    6 ++++++
 include/net/bluetooth/hci_core.h |    2 ++
 net/bluetooth/hci_event.c        |   20 ++++++++++++++++++++
 3 files changed, 28 insertions(+)

diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index 88cbbda..348f4bf 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -932,6 +932,12 @@ struct hci_rp_le_read_buffer_size {
 	__u8     le_max_pkt;
 } __packed;
 
+#define HCI_OP_LE_READ_ADV_TX_POWER	0x2007
+struct hci_rp_le_read_adv_tx_power {
+	__u8	status;
+	__s8	tx_power;
+} __packed;
+
 #define HCI_OP_LE_SET_SCAN_PARAM	0x200b
 struct hci_cp_le_set_scan_param {
 	__u8    type;
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 9fe8e2d..8260bf2 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -278,6 +278,8 @@ struct hci_dev {
 	struct work_struct	le_scan;
 	struct le_scan_params	le_scan_params;
 
+	__s8			adv_tx_power;
+
 	int (*open)(struct hci_dev *hdev);
 	int (*close)(struct hci_dev *hdev);
 	int (*flush)(struct hci_dev *hdev);
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 78f1af5..fd5a51c 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -594,6 +594,9 @@ static void le_init(struct hci_dev *hdev)
 {
 	/* Read LE Buffer Size */
 	hci_send_cmd(hdev, HCI_OP_LE_READ_BUFFER_SIZE, 0, NULL);
+
+	/* Read LE Advertising Channel TX Power */
+	hci_send_cmd(hdev, HCI_OP_LE_READ_ADV_TX_POWER, 0, NULL);
 }
 
 static void hci_setup(struct hci_dev *hdev)
@@ -1073,6 +1076,19 @@ static void hci_cc_le_read_buffer_size(struct hci_dev *hdev,
 	hci_req_complete(hdev, HCI_OP_LE_READ_BUFFER_SIZE, rp->status);
 }
 
+static void hci_cc_le_read_adv_tx_power(struct hci_dev *hdev,
+					struct sk_buff *skb)
+{
+	struct hci_rp_le_read_adv_tx_power *rp = (void *) skb->data;
+
+	BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
+
+	if (!rp->status)
+		hdev->adv_tx_power = rp->tx_power;
+
+	hci_req_complete(hdev, HCI_OP_LE_READ_ADV_TX_POWER, rp->status);
+}
+
 static void hci_cc_le_set_event_mask(struct hci_dev *hdev, struct sk_buff *skb)
 {
 	__u8 status = *((__u8 *) skb->data);
@@ -2505,6 +2521,10 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
 		hci_cc_le_read_buffer_size(hdev, skb);
 		break;
 
+	case HCI_OP_LE_READ_ADV_TX_POWER:
+		hci_cc_le_read_adv_tx_power(hdev, skb);
+		break;
+
 	case HCI_OP_LE_SET_EVENT_MASK:
 		hci_cc_le_set_event_mask(hdev, skb);
 		break;
-- 
1.7.10.4


^ permalink raw reply related

* [PATCH 5/6] Bluetooth: Fix HCI command sending when powering on LE-only adapters
From: Johan Hedberg @ 2012-10-19 17:15 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1350666911-6334-1-git-send-email-johan.hedberg@gmail.com>

From: Johan Hedberg <johan.hedberg@intel.com>

This patch makes sure that we don't send BR/EDR-only commands for
LE-only adapters when they get powered on. Doing this would just cause
command errors.

Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
---
 net/bluetooth/mgmt.c |   34 +++++++++++++++++++++-------------
 1 file changed, 21 insertions(+), 13 deletions(-)

diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index e6d8f73..3fe74f4 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -2872,6 +2872,21 @@ static void settings_rsp(struct pending_cmd *cmd, void *data)
 	mgmt_pending_free(cmd);
 }
 
+static int set_bredr_scan(struct hci_dev *hdev)
+{
+	u8 scan = 0;
+
+	if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
+		scan |= SCAN_PAGE;
+	if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
+		scan |= SCAN_INQUIRY;
+
+	if (!scan)
+		return 0;
+
+	return hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
+}
+
 int mgmt_powered(struct hci_dev *hdev, u8 powered)
 {
 	struct cmd_lookup match = { NULL, hdev };
@@ -2883,19 +2898,12 @@ int mgmt_powered(struct hci_dev *hdev, u8 powered)
 	mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
 
 	if (powered) {
-		u8 scan = 0;
-
-		if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
-			scan |= SCAN_PAGE;
-		if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
-			scan |= SCAN_INQUIRY;
-
-		if (scan)
-			hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
-
-		update_class(hdev);
-		update_name(hdev, hdev->dev_name);
-		update_eir(hdev);
+		if (lmp_bredr_capable(hdev)) {
+			set_bredr_scan(hdev);
+			update_class(hdev);
+			update_name(hdev, hdev->dev_name);
+			update_eir(hdev);
+		}
 	} else {
 		u8 status = MGMT_STATUS_NOT_POWERED;
 		mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
-- 
1.7.10.4


^ permalink raw reply related

* [PATCH 4/6] Bluetooth: Add setting of the LE event mask
From: Johan Hedberg @ 2012-10-19 17:15 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1350666911-6334-1-git-send-email-johan.hedberg@gmail.com>

From: Johan Hedberg <johan.hedberg@intel.com>

This patch adds setting of the LE event mask to the HCI init procedure
for LE-capable controllers. Right now we only set the default mask which
is good enough for the events available in the 4.0 core specification.

Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
---
 net/bluetooth/hci_event.c |   20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index f4f0b8b..78f1af5 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -550,6 +550,13 @@ static void hci_setup_event_mask(struct hci_dev *hdev)
 		events[7] |= 0x20;	/* LE Meta-Event */
 
 	hci_send_cmd(hdev, HCI_OP_SET_EVENT_MASK, sizeof(events), events);
+
+	if (lmp_le_capable(hdev)) {
+		memset(events, 0, sizeof(events));
+		events[0] = 0x1f;
+		hci_send_cmd(hdev, HCI_OP_LE_SET_EVENT_MASK,
+			     sizeof(events), events);
+	}
 }
 
 static void bredr_init(struct hci_dev *hdev)
@@ -1066,6 +1073,15 @@ static void hci_cc_le_read_buffer_size(struct hci_dev *hdev,
 	hci_req_complete(hdev, HCI_OP_LE_READ_BUFFER_SIZE, rp->status);
 }
 
+static void hci_cc_le_set_event_mask(struct hci_dev *hdev, struct sk_buff *skb)
+{
+	__u8 status = *((__u8 *) skb->data);
+
+	BT_DBG("%s status 0x%2.2x", hdev->name, status);
+
+	hci_req_complete(hdev, HCI_OP_LE_SET_EVENT_MASK, status);
+}
+
 static void hci_cc_user_confirm_reply(struct hci_dev *hdev, struct sk_buff *skb)
 {
 	struct hci_rp_user_confirm_reply *rp = (void *) skb->data;
@@ -2489,6 +2505,10 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
 		hci_cc_le_read_buffer_size(hdev, skb);
 		break;
 
+	case HCI_OP_LE_SET_EVENT_MASK:
+		hci_cc_le_set_event_mask(hdev, skb);
+		break;
+
 	case HCI_OP_USER_CONFIRM_REPLY:
 		hci_cc_user_confirm_reply(hdev, skb);
 		break;
-- 
1.7.10.4


^ permalink raw reply related

* [PATCH 3/6] Bluetooth: Add initial support for LE-only controllers
From: Johan Hedberg @ 2012-10-19 17:15 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1350666911-6334-1-git-send-email-johan.hedberg@gmail.com>

From: Johan Hedberg <johan.hedberg@intel.com>

This patch splits off most the HCI init sequence commands from a fixed
set into a conditional one that is sent once the HCI_Read_Local_Features
command completes. This is necessary since many of the current fixed
commands are not allowed for LE-only controllers.

Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
---
 net/bluetooth/hci_core.c  |   35 ---------------------------
 net/bluetooth/hci_event.c |   58 +++++++++++++++++++++++++++++++++++++++++----
 2 files changed, 53 insertions(+), 40 deletions(-)

diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index b5a2be2..d7014b3 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -178,48 +178,13 @@ static void hci_reset_req(struct hci_dev *hdev, unsigned long opt)
 
 static void bredr_init(struct hci_dev *hdev)
 {
-	struct hci_cp_delete_stored_link_key cp;
-	__le16 param;
-	__u8 flt_type;
-
 	hdev->flow_ctl_mode = HCI_FLOW_CTL_MODE_PACKET_BASED;
 
-	/* Mandatory initialization */
-
 	/* Read Local Supported Features */
 	hci_send_cmd(hdev, HCI_OP_READ_LOCAL_FEATURES, 0, NULL);
 
 	/* Read Local Version */
 	hci_send_cmd(hdev, HCI_OP_READ_LOCAL_VERSION, 0, NULL);
-
-	/* Read Buffer Size (ACL mtu, max pkt, etc.) */
-	hci_send_cmd(hdev, HCI_OP_READ_BUFFER_SIZE, 0, NULL);
-
-	/* Read BD Address */
-	hci_send_cmd(hdev, HCI_OP_READ_BD_ADDR, 0, NULL);
-
-	/* Read Class of Device */
-	hci_send_cmd(hdev, HCI_OP_READ_CLASS_OF_DEV, 0, NULL);
-
-	/* Read Local Name */
-	hci_send_cmd(hdev, HCI_OP_READ_LOCAL_NAME, 0, NULL);
-
-	/* Read Voice Setting */
-	hci_send_cmd(hdev, HCI_OP_READ_VOICE_SETTING, 0, NULL);
-
-	/* Optional initialization */
-
-	/* Clear Event Filters */
-	flt_type = HCI_FLT_CLEAR_ALL;
-	hci_send_cmd(hdev, HCI_OP_SET_EVENT_FLT, 1, &flt_type);
-
-	/* Connection accept timeout ~20 secs */
-	param = __constant_cpu_to_le16(0x7d00);
-	hci_send_cmd(hdev, HCI_OP_WRITE_CA_TIMEOUT, 2, &param);
-
-	bacpy(&cp.bdaddr, BDADDR_ANY);
-	cp.delete_all = 1;
-	hci_send_cmd(hdev, HCI_OP_DELETE_STORED_LINK_KEY, sizeof(cp), &cp);
 }
 
 static void amp_init(struct hci_dev *hdev)
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 0383635..f4f0b8b 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -507,11 +507,13 @@ static void hci_setup_event_mask(struct hci_dev *hdev)
 	if (hdev->hci_ver < BLUETOOTH_VER_1_2)
 		return;
 
-	events[4] |= 0x01; /* Flow Specification Complete */
-	events[4] |= 0x02; /* Inquiry Result with RSSI */
-	events[4] |= 0x04; /* Read Remote Extended Features Complete */
-	events[5] |= 0x08; /* Synchronous Connection Complete */
-	events[5] |= 0x10; /* Synchronous Connection Changed */
+	if (lmp_bredr_capable(hdev)) {
+		events[4] |= 0x01; /* Flow Specification Complete */
+		events[4] |= 0x02; /* Inquiry Result with RSSI */
+		events[4] |= 0x04; /* Read Remote Extended Features Complete */
+		events[5] |= 0x08; /* Synchronous Connection Complete */
+		events[5] |= 0x10; /* Synchronous Connection Changed */
+	}
 
 	if (hdev->features[3] & LMP_RSSI_INQ)
 		events[4] |= 0x02; /* Inquiry Result with RSSI */
@@ -550,11 +552,57 @@ static void hci_setup_event_mask(struct hci_dev *hdev)
 	hci_send_cmd(hdev, HCI_OP_SET_EVENT_MASK, sizeof(events), events);
 }
 
+static void bredr_init(struct hci_dev *hdev)
+{
+	struct hci_cp_delete_stored_link_key cp;
+	__le16 param;
+	__u8 flt_type;
+
+	/* Read Buffer Size (ACL mtu, max pkt, etc.) */
+	hci_send_cmd(hdev, HCI_OP_READ_BUFFER_SIZE, 0, NULL);
+
+	/* Read Class of Device */
+	hci_send_cmd(hdev, HCI_OP_READ_CLASS_OF_DEV, 0, NULL);
+
+	/* Read Local Name */
+	hci_send_cmd(hdev, HCI_OP_READ_LOCAL_NAME, 0, NULL);
+
+	/* Read Voice Setting */
+	hci_send_cmd(hdev, HCI_OP_READ_VOICE_SETTING, 0, NULL);
+
+	/* Clear Event Filters */
+	flt_type = HCI_FLT_CLEAR_ALL;
+	hci_send_cmd(hdev, HCI_OP_SET_EVENT_FLT, 1, &flt_type);
+
+	/* Connection accept timeout ~20 secs */
+	param = __constant_cpu_to_le16(0x7d00);
+	hci_send_cmd(hdev, HCI_OP_WRITE_CA_TIMEOUT, 2, &param);
+
+	bacpy(&cp.bdaddr, BDADDR_ANY);
+	cp.delete_all = 1;
+	hci_send_cmd(hdev, HCI_OP_DELETE_STORED_LINK_KEY, sizeof(cp), &cp);
+}
+
+static void le_init(struct hci_dev *hdev)
+{
+	/* Read LE Buffer Size */
+	hci_send_cmd(hdev, HCI_OP_LE_READ_BUFFER_SIZE, 0, NULL);
+}
+
 static void hci_setup(struct hci_dev *hdev)
 {
 	if (hdev->dev_type != HCI_BREDR)
 		return;
 
+	/* Read BD Address */
+	hci_send_cmd(hdev, HCI_OP_READ_BD_ADDR, 0, NULL);
+
+	if (lmp_bredr_capable(hdev))
+		bredr_init(hdev);
+
+	if (lmp_le_capable(hdev))
+		le_init(hdev);
+
 	hci_setup_event_mask(hdev);
 
 	if (hdev->hci_ver > BLUETOOTH_VER_1_1)
-- 
1.7.10.4


^ permalink raw reply related

* [PATCH 2/6] Bluetooth: Fix LE MTU reporting for HCIGETDEVINFO
From: Johan Hedberg @ 2012-10-19 17:15 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1350666911-6334-1-git-send-email-johan.hedberg@gmail.com>

From: Johan Hedberg <johan.hedberg@intel.com>

This patch fixes the use of le_mtu and le_pkts values in the
HCIGETDEVINFO ioctl for LE-only controllers.

Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
---
 net/bluetooth/hci_core.c |    9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 23359ef..b5a2be2 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -1025,8 +1025,13 @@ int hci_get_dev_info(void __user *arg)
 	di.type     = (hdev->bus & 0x0f) | (hdev->dev_type << 4);
 	di.flags    = hdev->flags;
 	di.pkt_type = hdev->pkt_type;
-	di.acl_mtu  = hdev->acl_mtu;
-	di.acl_pkts = hdev->acl_pkts;
+	if (lmp_bredr_capable(hdev)) {
+		di.acl_mtu  = hdev->acl_mtu;
+		di.acl_pkts = hdev->acl_pkts;
+	} else {
+		di.acl_mtu  = hdev->le_mtu;
+		di.acl_pkts = hdev->le_pkts;
+	}
 	di.sco_mtu  = hdev->sco_mtu;
 	di.sco_pkts = hdev->sco_pkts;
 	di.link_policy = hdev->link_policy;
-- 
1.7.10.4


^ permalink raw reply related

* [PATCH 1/6] Bluetooth: Remove unnecessary LE init req from HCI core
From: Johan Hedberg @ 2012-10-19 17:15 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1350666911-6334-1-git-send-email-johan.hedberg@gmail.com>

From: Johan Hedberg <johan.hedberg@intel.com>

The necessary LE commands will be sent through hci_event.c when the
local supported features indicates LE support.

Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
---
 net/bluetooth/hci_core.c |   12 ------------
 1 file changed, 12 deletions(-)

diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 0ec776a..23359ef 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -273,14 +273,6 @@ static void hci_init_req(struct hci_dev *hdev, unsigned long opt)
 	}
 }
 
-static void hci_le_init_req(struct hci_dev *hdev, unsigned long opt)
-{
-	BT_DBG("%s", hdev->name);
-
-	/* Read LE buffer size */
-	hci_send_cmd(hdev, HCI_OP_LE_READ_BUFFER_SIZE, 0, NULL);
-}
-
 static void hci_scan_req(struct hci_dev *hdev, unsigned long opt)
 {
 	__u8 scan = opt;
@@ -687,10 +679,6 @@ int hci_dev_open(__u16 dev)
 
 		ret = __hci_request(hdev, hci_init_req, 0, HCI_INIT_TIMEOUT);
 
-		if (lmp_host_le_capable(hdev))
-			ret = __hci_request(hdev, hci_le_init_req, 0,
-					    HCI_INIT_TIMEOUT);
-
 		clear_bit(HCI_INIT, &hdev->flags);
 	}
 
-- 
1.7.10.4


^ permalink raw reply related

* [PATCH 0/6] Bluetooth: Add basic support for single-mode controllers
From: Johan Hedberg @ 2012-10-19 17:15 UTC (permalink / raw)
  To: linux-bluetooth

Hi,

This patch set adds initial support for single-mode controllers. I
haven't tested it yet with bluetoothd running but at least I'm able to
initialize and do some basic things with the virtual single-mode
controllers provided by b1ee.com (you can use emulator/b1ee to test
this).

FWIW, I've also tested that this doesn't break anything with the init
sequence for various other controllers that I have (includes 1.1, 1.2,
2.0, 2.1 and 4.0 controllers from several manufacturers).

Johan


^ permalink raw reply

* [PATCH] Bluetooth: Fix having bogus entries in mgmt_read_index_list reply
From: Johan Hedberg @ 2012-10-19 17:10 UTC (permalink / raw)
  To: linux-bluetooth

From: Johan Hedberg <johan.hedberg@intel.com>

The mgmt_read_index_list uses one loop to calculate the max needed size
of its response with the help of an upper-bound of the controller count.
The second loop is more strict as it checks for HCI_SETUP (which might
have gotten set after the first loop) and could result in some indexes
being skipped. Because of this the function needs to readjust the event
length and index count after filling in the response array.

Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
Cc: stable@vger.kernel.org
---
 net/bluetooth/mgmt.c |   11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index b127b88..e6d8f73 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -326,7 +326,7 @@ static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data,
 	struct hci_dev *d;
 	size_t rp_len;
 	u16 count;
-	int i, err;
+	int err;
 
 	BT_DBG("sock %p", sk);
 
@@ -347,9 +347,7 @@ static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data,
 		return -ENOMEM;
 	}
 
-	rp->num_controllers = cpu_to_le16(count);
-
-	i = 0;
+	count = 0;
 	list_for_each_entry(d, &hci_dev_list, list) {
 		if (test_bit(HCI_SETUP, &d->dev_flags))
 			continue;
@@ -357,10 +355,13 @@ static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data,
 		if (!mgmt_valid_hdev(d))
 			continue;
 
-		rp->index[i++] = cpu_to_le16(d->id);
+		rp->index[count++] = cpu_to_le16(d->id);
 		BT_DBG("Added hci%u", d->id);
 	}
 
+	rp->num_controllers = cpu_to_le16(count);
+	rp_len = sizeof(*rp) + (2 * count);
+
 	read_unlock(&hci_dev_list_lock);
 
 	err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, 0, rp,
-- 
1.7.10.4


^ permalink raw reply related

* Re: [PATCHv3 10/18] Bluetooth: Add logical link confirm
From: Mat Martineau @ 2012-10-19 16:44 UTC (permalink / raw)
  To: Andrei Emeltchenko; +Cc: linux-bluetooth, gustavo, sunnyk, marcel
In-Reply-To: <20121019075355.GA4249@aemeltch-MOBL1>


Hi Andrei -

On Fri, 19 Oct 2012, Andrei Emeltchenko wrote:

> Hi Mat,
>
> On Thu, Oct 18, 2012 at 10:58:42AM -0700, Mat Martineau wrote:
>> The logical link confirm callback is executed when the AMP controller
>> completes its logical link setup.  During a channel move, a newly
>> formed logical link allows a move responder to send a move channel
>> response.  A move initiator will send a move channel confirm.  A
>> failed logical link will end the channel move and send an appropriate
>> response or confirm command indicating a failure.
>>
>> If the channel is being created on an AMP controller, L2CAP
>> configuration is started after the logical link is set up.
>
> Is L2CAP configuration started after channel is created which is happening
> after physical link is created? After Logical link establishment we finish
> EFS configuration process.

I need to rephrase that last sentence to say "configuration is 
completed after the logical link is set up".

>
>>
>> Signed-off-by: Mat Martineau <mathewm@codeaurora.org>
>> ---
>>  net/bluetooth/l2cap_core.c | 120 ++++++++++++++++++++++++++++++++++++++++++++-
>>  1 file changed, 118 insertions(+), 2 deletions(-)
>>
>> diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
>> index 7e50aa4..8e50685 100644
>> --- a/net/bluetooth/l2cap_core.c
>> +++ b/net/bluetooth/l2cap_core.c
>> @@ -3799,6 +3799,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn,
>>  		goto unlock;
>>  	}
>>
>> +	chan->ident = cmd->ident;
>>  	l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP, len, rsp);
>>  	chan->num_conf_rsp++;
>>
>> @@ -4241,11 +4242,126 @@ static void l2cap_send_move_chan_cfm_rsp(struct l2cap_conn *conn, u8 ident,
>>  	l2cap_send_cmd(conn, ident, L2CAP_MOVE_CHAN_CFM_RSP, sizeof(rsp), &rsp);
>>  }
>>
>> +static void l2cap_logical_fail(struct l2cap_chan *chan)
>> +{
>> +	/* Logical link setup failed */
>> +	if (chan->state != BT_CONNECTED) {
>> +		/* Create channel failure, disconnect */
>> +		l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
>> +	} else if (chan->move_role == L2CAP_MOVE_ROLE_RESPONDER) {
>> +		l2cap_move_revert(chan);
>> +		chan->move_role = L2CAP_MOVE_ROLE_NONE;
>> +		chan->move_state = L2CAP_MOVE_STABLE;
>> +		l2cap_send_move_chan_rsp(chan->conn, chan->ident, chan->dcid,
>> +					 L2CAP_MR_NOT_SUPP);
>> +	} else if (chan->move_role == L2CAP_MOVE_ROLE_INITIATOR) {
>> +		if (chan->move_state == L2CAP_MOVE_WAIT_LOGICAL_COMP ||
>> +		    chan->move_state == L2CAP_MOVE_WAIT_LOGICAL_CFM) {
>> +			/* Remote has only sent pending or
>> +			 * success responses, clean up
>> +			 */
>> +			l2cap_move_revert(chan);
>> +			chan->move_role = L2CAP_MOVE_ROLE_NONE;
>> +			chan->move_state = L2CAP_MOVE_STABLE;
>> +		}
>> +
>> +		/* Other amp move states imply that the move
>> +		 * has already aborted
>> +		 */
>> +		l2cap_send_move_chan_cfm(chan->conn, chan, chan->scid,
>> +					 L2CAP_MC_UNCONFIRMED);
>> +		__set_chan_timer(chan, L2CAP_MOVE_TIMEOUT);
>> +	}
>> +
>> +	chan->hs_hchan = NULL;
>> +	chan->hs_hcon = NULL;
>> +
>> +	/* Placeholder - free logical link */
>> +}
>> +
>> +static void l2cap_logical_create_channel(struct l2cap_chan *chan,
>> +					 struct hci_chan *hchan)
>> +{
>
> This is bad name IMO, the function finish L2CAP EFS configuration not
> creating logical link.

l2cap_logical_cfm had three paths:  failure, create channel, and move 
channel.  I was trying to come up with function names that reflected 
which activity was going on.  Maybe l2cap_logical_finish_create() and 
l2cap_logical_finish_move() would be more clear?


>> +	struct l2cap_conf_rsp rsp;
>> +	u8 code;
>> +
>> +	chan->hs_hcon = hchan->conn;
>> +	chan->hs_hcon->l2cap_data = chan->conn;
>> +
>> +	code = l2cap_build_conf_rsp(chan, &rsp,
>> +				    L2CAP_CONF_SUCCESS, 0);
>> +	l2cap_send_cmd(chan->conn, chan->ident, L2CAP_CONF_RSP, code,
>> +		       &rsp);
>> +	set_bit(CONF_OUTPUT_DONE, &chan->conf_state);
>> +
>> +	if (test_bit(CONF_INPUT_DONE, &chan->conf_state)) {
>> +		int err = 0;
>> +
>> +		set_default_fcs(chan);
>> +
>> +		err = l2cap_ertm_init(chan);
>> +		if (err < 0)
>> +			l2cap_send_disconn_req(chan->conn, chan, -err);
>> +		else
>> +			l2cap_chan_ready(chan);
>> +	}
>> +}
>> +
>> +static void l2cap_logical_move_channel(struct l2cap_chan *chan,
>> +				       struct hci_chan *hchan)
>> +{
>> +	chan->hs_hcon = hchan->conn;
>> +	chan->hs_hcon->l2cap_data = chan->conn;
>> +
>> +	BT_DBG("move_state %d", chan->move_state);
>> +
>> +	switch (chan->move_state) {
>> +	case L2CAP_MOVE_WAIT_LOGICAL_COMP:
>> +		/* Move confirm will be sent after a success
>> +		 * response is received
>> +		 */
>> +		chan->move_state = L2CAP_MOVE_WAIT_RSP_SUCCESS;
>> +		break;
>> +	case L2CAP_MOVE_WAIT_LOGICAL_CFM:
>> +		if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
>> +			chan->move_state = L2CAP_MOVE_WAIT_LOCAL_BUSY;
>> +		} else if (chan->move_role == L2CAP_MOVE_ROLE_INITIATOR) {
>> +			chan->move_state = L2CAP_MOVE_WAIT_CONFIRM_RSP;
>> +			l2cap_send_move_chan_cfm(chan->conn, chan, chan->scid,
>> +						 L2CAP_MR_SUCCESS);
>> +			__set_chan_timer(chan, L2CAP_MOVE_TIMEOUT);
>> +		} else if (chan->move_role == L2CAP_MOVE_ROLE_RESPONDER) {
>> +			chan->move_state = L2CAP_MOVE_WAIT_CONFIRM;
>> +			l2cap_send_move_chan_rsp(chan->conn, chan->ident,
>> +						 chan->dcid, L2CAP_MR_SUCCESS);
>> +		}
>> +		break;
>> +	default:
>> +		/* Move was not in expected state, free the channel */
>> +		chan->hs_hchan = NULL;
>> +		chan->hs_hcon = NULL;
>> +
>> +		/* Placeholder - free the logical link */
>> +
>> +		chan->move_state = L2CAP_MOVE_STABLE;
>> +	}
>> +}
>> +
>> +/* Call with chan locked */
>>  static void l2cap_logical_cfm(struct l2cap_chan *chan, struct hci_chan *hchan,
>>  			      u8 status)
>>  {
>> -	/* Placeholder */
>> -	return;
>> +	BT_DBG("chan %p, hchan %p, status %d", chan, hchan, status);
>> +
>> +	if (status) {
>> +		l2cap_logical_fail(chan);
>> +	} else if (chan->state != BT_CONNECTED) {
>> +		/* Ignore logical link if channel is on BR/EDR */
>> +		if (chan->local_amp_id)
>> +			l2cap_logical_create_channel(chan, hchan);
>> +	} else {
>> +		l2cap_logical_move_channel(chan, hchan);
>> +	}
>>  }
>>
>>  static inline int l2cap_move_channel_req(struct l2cap_conn *conn,
>> --
>> 1.7.12.3

Regards,

--
Mat Martineau

Employee of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation


^ permalink raw reply

* Re: [PATCHv3 18/18] Bluetooth: Start channel move when socket option is changed
From: Mat Martineau @ 2012-10-19 16:16 UTC (permalink / raw)
  To: Andrei Emeltchenko; +Cc: linux-bluetooth, gustavo, sunnyk, marcel
In-Reply-To: <20121019093756.GM4249@aemeltch-MOBL1>


Hi Andrei -

On Fri, 19 Oct 2012, Andrei Emeltchenko wrote:

> Hi Mat,
>
> On Thu, Oct 18, 2012 at 10:58:50AM -0700, Mat Martineau wrote:
>> Channel moves are triggered by changes to the BT_CHANNEL_POLICY
>> sockopt when an ERTM or streaming-mode channel is connected.
>>
>> Moves are only started if enable_hs is true.
>>
>> Signed-off-by: Mat Martineau <mathewm@codeaurora.org>
>> Acked-by: Marcel Holtmann <marcel@holtmann.org>
>> ---
>>  include/net/bluetooth/l2cap.h |  1 +
>>  net/bluetooth/l2cap_core.c    | 20 ++++++++++++++++++++
>>  net/bluetooth/l2cap_sock.c    |  5 +++++
>>  3 files changed, 26 insertions(+)
>>
>> diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
>> index b4c3c65..49783e9 100644
>> --- a/include/net/bluetooth/l2cap.h
>> +++ b/include/net/bluetooth/l2cap.h
>> @@ -809,5 +809,6 @@ void l2cap_chan_add(struct l2cap_conn *conn, 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);
>>  void l2cap_send_conn_req(struct l2cap_chan *chan);
>> +void l2cap_move_start(struct l2cap_chan *chan);
>>
>>  #endif /* __L2CAP_H */
>> diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
>> index 8fa46de..b3d3f4f 100644
>> --- a/net/bluetooth/l2cap_core.c
>> +++ b/net/bluetooth/l2cap_core.c
>> @@ -4452,6 +4452,26 @@ static void l2cap_logical_cfm(struct l2cap_chan *chan, struct hci_chan *hchan,
>>  	}
>>  }
>>
>> +void l2cap_move_start(struct l2cap_chan *chan)
>> +{
>> +	BT_DBG("chan %p", chan);
>> +
>> +	if (chan->local_amp_id == 0) {
>
> I would rather use "if (!chan->local_amp_id)" or event better if compare to
> use "if (chan->local_amp_id == HCI_BRDER_ID)

Ok, done.

>> +		if (chan->chan_policy != BT_CHANNEL_POLICY_AMP_PREFERRED)
>> +			return;
>> +		chan->move_role = L2CAP_MOVE_ROLE_INITIATOR;
>> +		chan->move_state = L2CAP_MOVE_WAIT_PREPARE;
>
> Isn't it a bit earlier to start move? We should first to query remote AMP
> controllers to find out AMP id, etc. Or how this supposed to work? Where
> do you move?

The move request isn't sent until after the remote AMP controllers 
have been queried.  Sending the AMP queries is part of the move 
process, so the channel move state machine takes it in to account as 
the MOVE_WAIT_PREPARE state.

When the userspace AMP API was defined, the BlueZ community settled on 
using the BT_CHANNEL_POLICY approach and not exporting the choice of 
remote AMP device to userspace.  The AMP manager is responsible for 
choosing the best available AMP controller (in practice so far, 
there's a maximum of one anyway).  The chosen controller ID is 
provided to L2CAP as the remote_amp_id parameter to 
l2cap_physical_cfm(), and L2CAP sends a move channel request with that 
ID.

>> +		/* Placeholder - start physical link setup */
>> +	} else {
>> +		chan->move_role = L2CAP_MOVE_ROLE_INITIATOR;
>> +		chan->move_state = L2CAP_MOVE_WAIT_RSP_SUCCESS;
>> +		chan->move_id = 0;
>> +		l2cap_move_start(chan);
>> +		l2cap_send_move_chan_req(chan, 0);
>> +		__set_chan_timer(chan, L2CAP_MOVE_TIMEOUT);
>> +	}
>> +}
>> +
>>  static void l2cap_do_create(struct l2cap_chan *chan, int result,
>>  			    u8 local_amp_id, u8 remote_amp_id)
>>  {
>> diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c
>> index 5fae2bd..7cb4d73 100644
>> --- a/net/bluetooth/l2cap_sock.c
>> +++ b/net/bluetooth/l2cap_sock.c
>> @@ -735,6 +735,11 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname,
>>  		}
>>
>>  		chan->chan_policy = (u8) opt;
>> +
>> +		if (sk->sk_state == BT_CONNECTED &&
>> +		    chan->move_role == L2CAP_MOVE_ROLE_NONE)
>> +			l2cap_move_start(chan);
>> +
>>  		break;
>>
>>  	default:
>> --
>> 1.7.12.3

Thanks,

--
Mat Martineau

Employee of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

^ permalink raw reply

* Re: [PATCH v6 01/16] doc: Add settings storage documentation
From: Marcel Holtmann @ 2012-10-19 16:12 UTC (permalink / raw)
  To: Frederic Danis; +Cc: linux-bluetooth
In-Reply-To: <50811E78.6060009@linux.intel.com>

Hi Fred,

> >> +Cache directory files
> >> +======================
> >> +
> >> +Each files, named by remote device address, contains 1 [General] group:
> >> +  [General]
> >> +  Name=device name a
> >
> > Is this the only thing we are storing in these files? Or are we planning
> > to store additional information at some point.
> >
> >> +Device directory files
> >> +======================
> >> +
> >> +Remote device info file will include a [General] group with device info,
> >> +[DeviceID], [LinkKey] and [LongTermKey] groups with related info:
> >> +  [General]
> >> +  Alias=
> >
> > Are we just doing the Alias here? We are not keeping the Name? In theory
> > we have a short name and full name actually. If we ever only got the
> > short name, we need to know that. Then we have to request the long name
> > next time.
> 
> Name is already stored in cache file. So I think we do not need to save 
> it also in device info file.
> 
> We may store both short and long names in the cache file.

I was assuming that the cache file is only used for LE devices with
static random addresses, but know I remember that we even need to store
the names for devices that we only discovered and not paired with.

Regards

Marcel



^ permalink raw reply

* Re: [RFC v0 13/15] profile: Rename org.bluez.Profile->ProfileAgent
From: Marcel Holtmann @ 2012-10-19 16:10 UTC (permalink / raw)
  To: Mikel Astiz; +Cc: linux-bluetooth, Mikel Astiz
In-Reply-To: <1350661172-18125-14-git-send-email-mikel.astiz.oss@gmail.com>

Hi Mikel,

> The interface represents an external component supporting a specific
> profile by implementing an agent. Therefore ProfileAgent is a more
> accurate name for the D-Bus interface.

actually I think Johan and I discussed this. And the reason for keeping
the name Profile is that the external component implements the profile.
It is not just an agent, it is the profile.

Regards

Marcel



^ permalink raw reply

* [RFC v0 15/15] profile: Add new org.bluez.Profile
From: Mikel Astiz @ 2012-10-19 15:39 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Mikel Astiz
In-Reply-To: <1350661172-18125-1-git-send-email-mikel.astiz.oss@gmail.com>

From: Mikel Astiz <mikel.astiz@bmw-carit.de>

Add a D-Bus interface to represent a profile that is supported by a
device, moving the profile-specific API in org.bluez.Device and
additionally exposing state information.
---
 doc/device-api.txt   |  23 -------
 doc/profile-api.txt  |  48 +++++++++++++++
 src/device-profile.c | 166 ++++++++++++++++++++++++++++++++++++++++++++++++++-
 src/device-profile.h |   1 +
 src/device.c         |   3 +
 5 files changed, 217 insertions(+), 24 deletions(-)
 create mode 100644 doc/profile-api.txt

diff --git a/doc/device-api.txt b/doc/device-api.txt
index c1f2361..b0145e0 100644
--- a/doc/device-api.txt
+++ b/doc/device-api.txt
@@ -70,29 +70,6 @@ Methods		dict DiscoverServices(string pattern)
 
 			Possible errors: org.bluez.Error.NotConnected
 
-		void ConnectProfile(string uuid)
-
-			This method connects a specific profile of this
-			device. The profile needs to be registered client
-			profile.
-
-			Possible errors: org.bluez.Error.DoesNotExist
-					 org.bluez.Error.AlreadyConnected
-					 org.bluez.Error.ConnectFailed
-
-		void DisconnectProfile(string uuid)
-
-			This method disconnects a specific profile of
-			this device. The profile needs to be registered
-			client profile.
-
-			There is no connection tracking for a profile, so
-			as long as the profile is registered this will always
-			succeed.
-
-			Possible errors: org.bluez.Error.DoesNotExist
-					 org.bluez.Error.NotConnected
-
 		void Pair(object agent, string capability)
 
 			This method will connect to the remote device,
diff --git a/doc/profile-api.txt b/doc/profile-api.txt
new file mode 100644
index 0000000..9540b7a
--- /dev/null
+++ b/doc/profile-api.txt
@@ -0,0 +1,48 @@
+BlueZ D-Bus Profile API description
+***********************************
+
+Copyright (C) 2012  BMW Car IT GmbH. All rights reserved.
+
+
+Profile hierarchy
+=================
+
+Service		unique name
+Interface	org.bluez.Profile
+Object path	freely definable
+
+Object path	[variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX/
+								profileZZZ
+
+Methods		void Connect()
+
+			This method connects a specific profile of this
+			device. The profile needs to be registered client
+			profile.
+
+			Possible errors: org.bluez.Error.AlreadyConnected
+					 org.bluez.Error.ConnectFailed
+					 org.bluez.Error.Canceled
+					 org.bluez.Error.AgentNotAvailable
+
+		void Disconnect()
+
+			This method disconnects a specific profile of
+			this device. The profile needs to be registered
+			client profile.
+
+			There is no connection tracking for a profile, so
+			as long as the profile is registered this will always
+			succeed.
+
+			Possible errors: org.bluez.Error.NotConnected
+
+Properties	string State [readonly]
+
+			Indicates the state of the connection.  Possible
+			values are:
+				"disconnected": profile disconnected
+				"connecting": outgoing or incoming connection
+						attempt going on, including
+						local agent authorization
+				"connected": profile connected
diff --git a/src/device-profile.c b/src/device-profile.c
index ea796ac..d4b72d1 100644
--- a/src/device-profile.c
+++ b/src/device-profile.c
@@ -41,19 +41,27 @@
 #include <bluetooth/mgmt.h>
 
 #include <glib.h>
+#include <dbus/dbus.h>
+#include <gdbus.h>
 
 #include "log.h"
 
+#include "dbus-common.h"
+#include "error.h"
 #include "adapter.h"
 #include "device.h"
 #include "profile.h"
 #include "device-profile.h"
 
+#define DEVICE_PROFILE_INTERFACE "org.bluez.Profile"
+
 struct btd_device_profile {
 	gint			ref;
 	struct btd_device	*device;
 	struct btd_profile	*profile;
+	gchar			*path;
 	profile_state_t		state;
+	DBusMessage		*msg;
 };
 
 static char *str_state[] = {
@@ -62,6 +70,20 @@ static char *str_state[] = {
 	"PROFILE_STATE_CONNECTED",
 };
 
+static const char *state2str(profile_state_t state)
+{
+	switch (state) {
+	case PROFILE_STATE_DISCONNECTED:
+		return "disconnected";
+	case PROFILE_STATE_CONNECTING:
+		return "connecting";
+	case PROFILE_STATE_CONNECTED:
+		return "connected";
+	}
+
+	return NULL;
+}
+
 struct btd_device *device_profile_get_device(struct btd_device_profile *dp)
 {
 	return dp->device;
@@ -75,12 +97,131 @@ struct btd_profile *device_profile_get_profile(struct btd_device_profile *dp)
 void device_profile_set_state(struct btd_device_profile *dp,
 							profile_state_t state)
 {
-	DBG("State changed %p: %s -> %s", dp, str_state[dp->state],
+	DBG("State changed %s: %s -> %s", dp->path, str_state[dp->state],
 							str_state[state]);
 
 	dp->state = state;
+
+	g_dbus_emit_property_changed(btd_get_dbus_connection(),
+					dp->path, DEVICE_PROFILE_INTERFACE,
+					"State");
+}
+
+static void connect_cb(struct btd_device_profile *dp, int err)
+{
+	DBusMessage *msg = dp->msg;
+	DBusMessage *reply;
+
+	if (err == 0) {
+		reply = dbus_message_new_method_return(msg);
+		device_profile_set_state(dp, PROFILE_STATE_CONNECTED);
+	} else {
+		reply = btd_error_failed(msg, strerror(-err));
+		device_profile_set_state(dp, PROFILE_STATE_DISCONNECTED);
+	}
+
+	g_dbus_send_message(btd_get_dbus_connection(), reply);
+
+	dbus_message_unref(msg);
+	dp->msg = NULL;
+}
+
+static DBusMessage *dp_connect(DBusConnection *conn, DBusMessage *msg,
+							void *user_data)
+{
+	struct btd_device_profile *dp = user_data;
+	int err;
+
+	if (dp->state != PROFILE_STATE_DISCONNECTED)
+		return btd_error_already_connected(msg);
+
+	if (dp->msg != NULL)
+		return btd_error_busy(msg);
+
+	err = dp->profile->connect(dp, connect_cb);
+	if (err < 0)
+		return btd_error_failed(msg, strerror(-err));
+
+	dp->msg = dbus_message_ref(msg);
+	device_profile_set_state(dp, PROFILE_STATE_CONNECTING);
+
+	return NULL;
+}
+
+static gboolean disconnect_cb_continue(gpointer user_data)
+{
+	struct btd_device_profile *dp = user_data;
+
+	g_dbus_send_message(btd_get_dbus_connection(), dp->msg);
+	dbus_message_unref(dp->msg);
+	dp->msg = NULL;
+
+	return FALSE;
+}
+
+static void disconnect_cb(struct btd_device_profile *dp, int err)
+{
+	DBusMessage *msg = dp->msg;
+	DBusMessage *reply;
+
+	if (err == 0) {
+		reply = dbus_message_new_method_return(msg);
+		device_profile_set_state(dp, PROFILE_STATE_DISCONNECTED);
+	} else
+		reply = btd_error_failed(msg, strerror(-err));
+
+	dbus_message_unref(msg);
+	dp->msg = reply;
+
+	g_idle_add(disconnect_cb_continue, dp);
 }
 
+static DBusMessage *dp_disconnect(DBusConnection *conn, DBusMessage *msg,
+							void *user_data)
+{
+	struct btd_device_profile *dp = user_data;
+	int err;
+
+	if (dp->state == PROFILE_STATE_DISCONNECTED)
+		return btd_error_not_connected(msg);
+
+	if (dp->msg != NULL)
+		return btd_error_busy(msg);
+
+	dp->msg = dbus_message_ref(msg);
+
+	err = dp->profile->disconnect(dp, disconnect_cb);
+	if (err < 0) {
+		dbus_message_unref(dp->msg);
+		dp->msg = NULL;
+		return btd_error_failed(msg, strerror(-err));
+	}
+
+	return NULL;
+}
+
+static gboolean dp_property_get_state(const GDBusPropertyTable *property,
+					DBusMessageIter *iter, void *data)
+{
+	struct btd_device_profile *dp = data;
+	const char *state = state2str(dp->state);
+
+	dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &state);
+
+	return TRUE;
+}
+
+static const GDBusMethodTable device_profile_methods[] = {
+	{ GDBUS_ASYNC_METHOD("Connect", NULL, NULL, dp_connect) },
+	{ GDBUS_ASYNC_METHOD("Disconnect", NULL, NULL, dp_disconnect) },
+	{ }
+};
+
+static const GDBusPropertyTable device_profile_properties[] = {
+	{ "State", "s", dp_property_get_state },
+	{ }
+};
+
 struct btd_device_profile *device_profile_create(struct btd_device *device,
 						struct btd_profile *profile)
 {
@@ -96,10 +237,29 @@ struct btd_device_profile *device_profile_create(struct btd_device *device,
 	dp->device = btd_device_ref(device);
 	dp->profile = profile;
 	dp->state = PROFILE_STATE_DISCONNECTED;
+	dp->path = g_strdup_printf("%s/%s", device_get_path(device),
+								profile->name);
+	g_strdelimit(dp->path, "-", '_');
+
+	if (!g_dbus_register_interface(btd_get_dbus_connection(),
+					dp->path, DEVICE_PROFILE_INTERFACE,
+					device_profile_methods, NULL,
+					device_profile_properties, dp,
+					NULL)) {
+		error("Device profile init failed on path %s", dp->path);
+		device_profile_unref(dp);
+		return NULL;
+	}
 
 	return dp;
 }
 
+void device_profile_unregister(struct btd_device_profile *dp)
+{
+	g_dbus_unregister_interface(btd_get_dbus_connection(),
+					dp->path, DEVICE_PROFILE_INTERFACE);
+}
+
 struct btd_device_profile *device_profile_ref(struct btd_device_profile *dp)
 {
 	dp->ref++;
@@ -120,5 +280,9 @@ void device_profile_unref(struct btd_device_profile *dp)
 
 	btd_device_unref(dp->device);
 
+	if (dp->msg)
+		dbus_message_unref(dp->msg);
+
+	g_free(dp->path);
 	g_free(dp);
 }
diff --git a/src/device-profile.h b/src/device-profile.h
index ef75d79..db03d79 100644
--- a/src/device-profile.h
+++ b/src/device-profile.h
@@ -31,6 +31,7 @@ struct btd_device_profile;
 
 struct btd_device_profile *device_profile_create(struct btd_device *device,
 						struct btd_profile *profile);
+void device_profile_unregister(struct btd_device_profile *dp);
 
 struct btd_device_profile *device_profile_ref(struct btd_device_profile *dp);
 void device_profile_unref(struct btd_device_profile *dp);
diff --git a/src/device.c b/src/device.c
index 37eddef..2a73f2f 100644
--- a/src/device.c
+++ b/src/device.c
@@ -860,6 +860,7 @@ static void profile_remove(gpointer p)
 	struct btd_profile *profile = device_profile_get_profile(dp);
 
 	profile->device_remove(profile, device);
+	device_profile_unregister(dp);
 	device_profile_unref(dp);
 }
 
@@ -1919,6 +1920,7 @@ void device_remove_profile(gpointer a, gpointer b)
 
 	device->profiles = g_slist_remove_link(device->profiles, l);
 
+	device_profile_unregister(dp);
 	device_profile_unref(dp);
 
 	profile->device_remove(profile, device);
@@ -2007,6 +2009,7 @@ static void device_remove_profiles(struct btd_device *device, GSList *uuids)
 		profile->device_remove(profile, device);
 		device->profiles = g_slist_remove_link(device->profiles, l);
 
+		device_profile_unregister(dp);
 		device_profile_unref(dp);
 	}
 }
-- 
1.7.11.7


^ permalink raw reply related

* [RFC v0 14/15] profile: Add object to represent device-profile
From: Mikel Astiz @ 2012-10-19 15:39 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Mikel Astiz
In-Reply-To: <1350661172-18125-1-git-send-email-mikel.astiz.oss@gmail.com>

From: Mikel Astiz <mikel.astiz@bmw-carit.de>

An instance of bdm_device_profile represents a profile that has been
probed for a given device, including the state of the connection.
---
 Makefile.am                |   1 +
 audio/manager.c            |  32 ++++++------
 profiles/input/device.c    |  21 ++++----
 profiles/input/device.h    |   8 +--
 profiles/network/manager.c |  57 ++++++++++-----------
 src/device-profile.c       | 124 +++++++++++++++++++++++++++++++++++++++++++++
 src/device-profile.h       |  42 +++++++++++++++
 src/device.c               | 107 +++++++++++++++++++++++++++-----------
 src/profile.c              |  45 +++++++++-------
 src/profile.h              |  11 ++--
 10 files changed, 334 insertions(+), 114 deletions(-)
 create mode 100644 src/device-profile.c
 create mode 100644 src/device-profile.h

diff --git a/Makefile.am b/Makefile.am
index 35b1520..4fa341e 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -311,6 +311,7 @@ src_bluetoothd_SOURCES = $(gdbus_sources) $(builtin_sources) \
 			src/manager.h src/manager.c \
 			src/adapter.h src/adapter.c \
 			src/profile.h src/profile.c \
+			src/device-profile.h src/device-profile.c \
 			src/device.h src/device.c src/attio.h \
 			src/dbus-common.c src/dbus-common.h \
 			src/event.h src/event.c src/eir.h src/eir.c \
diff --git a/audio/manager.c b/audio/manager.c
index 77e3540..042d131 100644
--- a/audio/manager.c
+++ b/audio/manager.c
@@ -54,6 +54,7 @@
 #include "../src/manager.h"
 #include "../src/device.h"
 #include "../src/profile.h"
+#include "../src/device-profile.h"
 
 #include "log.h"
 #include "device.h"
@@ -84,9 +85,8 @@ struct audio_adapter {
 };
 
 struct profile_req {
-	struct btd_device	*device;
-	struct btd_profile	*profile;
-	btd_profile_cb		cb;
+	struct btd_device_profile	*dp;
+	btd_device_profile_cb		cb;
 };
 
 static gboolean auto_connect = TRUE;
@@ -782,15 +782,13 @@ static int avrcp_probe(struct btd_profile *p, struct btd_device *device,
 	return 0;
 }
 
-static struct profile_req *new_profile_request(struct btd_device *dev,
-						struct btd_profile *profile,
-						btd_profile_cb cb)
+static struct profile_req *new_profile_request(struct btd_device_profile *dp,
+						btd_device_profile_cb cb)
 {
 	struct profile_req *req;
 
 	req  = g_new0(struct profile_req, 1);
-	req->device = dev;
-	req->profile = profile;
+	req->dp = dp;
 	req->cb = cb;
 
 	return req;
@@ -800,15 +798,15 @@ static void profile_cb(struct audio_device *dev, int err, void *data)
 {
 	struct profile_req *req = data;
 
-	req->cb(req->profile, req->device, err);
+	req->cb(req->dp, err);
 
 	g_free(req);
 }
 
-static int a2dp_source_connect(struct btd_device *dev,
-						struct btd_profile *profile,
-						btd_profile_cb cb)
+static int a2dp_source_connect(struct btd_device_profile *dp,
+						btd_device_profile_cb cb)
 {
+	struct btd_device *dev = device_profile_get_device(dp);
 	struct audio_device *audio_dev;
 	struct profile_req *req;
 	int err;
@@ -819,7 +817,7 @@ static int a2dp_source_connect(struct btd_device *dev,
 		return -1;
 	}
 
-	req = new_profile_request(dev, profile, cb);
+	req = new_profile_request(dp, cb);
 
 	err = source_connect(audio_dev, profile_cb, req);
 	if (err < 0) {
@@ -830,10 +828,10 @@ static int a2dp_source_connect(struct btd_device *dev,
 	return 0;
 }
 
-static int a2dp_source_disconnect(struct btd_device *dev,
-						struct btd_profile *profile,
-						btd_profile_cb cb)
+static int a2dp_source_disconnect(struct btd_device_profile *dp,
+						btd_device_profile_cb cb)
 {
+	struct btd_device *dev = device_profile_get_device(dp);
 	struct audio_device *audio_dev;
 	struct profile_req *req;
 	int err;
@@ -844,7 +842,7 @@ static int a2dp_source_disconnect(struct btd_device *dev,
 		return -1;
 	}
 
-	req = new_profile_request(dev, profile, cb);
+	req = new_profile_request(dp, cb);
 
 	err = source_disconnect(audio_dev, profile_cb, req);
 	if (err < 0) {
diff --git a/profiles/input/device.c b/profiles/input/device.c
index fbc3d6f..4867e34 100644
--- a/profiles/input/device.c
+++ b/profiles/input/device.c
@@ -45,6 +45,7 @@
 #include "../src/adapter.h"
 #include "../src/device.h"
 #include "../src/profile.h"
+#include "../src/device-profile.h"
 #include "../src/storage.h"
 #include "../src/manager.h"
 #include "../src/dbus-common.h"
@@ -67,8 +68,8 @@ struct pending_connect {
 	bool local;
 	union {
 		struct {
-			struct btd_profile *profile;
-			btd_profile_cb cb;
+			struct btd_device_profile *dp;
+			btd_device_profile_cb cb;
 		} p;
 		DBusMessage *msg;
 	};
@@ -528,7 +529,7 @@ static void connect_reply(struct input_device *idev, int err,
 		error("%s", err_msg);
 
 	if (!pending->local) {
-		pending->p.cb(pending->p.profile, idev->device, err);
+		pending->p.cb(pending->p.dp, err);
 		g_free(pending);
 		return;
 	}
@@ -657,9 +658,10 @@ static int dev_connect(struct input_device *idev)
 	return -EIO;
 }
 
-int input_device_connect(struct btd_device *dev, struct btd_profile *profile,
-							btd_profile_cb cb)
+int input_device_connect(struct btd_device_profile *dp,
+						btd_device_profile_cb cb)
 {
+	struct btd_device *dev = device_profile_get_device(dp);
 	struct input_device *idev;
 
 	idev = find_device_by_path(devices, device_get_path(dev));
@@ -674,7 +676,7 @@ int input_device_connect(struct btd_device *dev, struct btd_profile *profile,
 
 	idev->pending = g_new0(struct pending_connect, 1);
 	idev->pending->local = false;
-	idev->pending->p.profile = profile;
+	idev->pending->p.dp = dp;
 	idev->pending->p.cb = cb;
 
 	return dev_connect(idev);
@@ -700,9 +702,10 @@ static DBusMessage *local_connect(DBusConnection *conn, DBusMessage *msg,
 	return NULL;
 }
 
-int input_device_disconnect(struct btd_device *dev, struct btd_profile *profile,
-							btd_profile_cb cb)
+int input_device_disconnect(struct btd_device_profile *dp,
+						btd_device_profile_cb cb)
 {
+	struct btd_device *dev = device_profile_get_device(dp);
 	struct input_device *idev;
 	int err;
 
@@ -715,7 +718,7 @@ int input_device_disconnect(struct btd_device *dev, struct btd_profile *profile,
 		return err;
 
 	if (cb)
-		cb(profile, dev, 0);
+		cb(dp, 0);
 
 	return 0;
 }
diff --git a/profiles/input/device.h b/profiles/input/device.h
index d68798c..18924a0 100644
--- a/profiles/input/device.h
+++ b/profiles/input/device.h
@@ -36,7 +36,7 @@ int input_device_set_channel(const bdaddr_t *src, const bdaddr_t *dst, int psm,
 							GIOChannel *io);
 int input_device_close_channels(const bdaddr_t *src, const bdaddr_t *dst);
 
-int input_device_connect(struct btd_device *dev, struct btd_profile *profile,
-							btd_profile_cb cb);
-int input_device_disconnect(struct btd_device *dev, struct btd_profile *profile,
-							btd_profile_cb cb);
+int input_device_connect(struct btd_device_profile *dp,
+						btd_device_profile_cb cb);
+int input_device_disconnect(struct btd_device_profile *dp,
+						btd_device_profile_cb cb);
diff --git a/profiles/network/manager.c b/profiles/network/manager.c
index 87d263a..6917b5b 100644
--- a/profiles/network/manager.c
+++ b/profiles/network/manager.c
@@ -40,6 +40,7 @@
 #include "adapter.h"
 #include "device.h"
 #include "profile.h"
+#include "device-profile.h"
 #include "manager.h"
 #include "common.h"
 #include "connection.h"
@@ -48,9 +49,8 @@
 static gboolean conf_security = TRUE;
 
 struct connect_req {
-	struct btd_device	*device;
-	struct btd_profile	*profile;
-	btd_profile_cb		cb;
+	struct btd_device_profile	*dp;
+	btd_device_profile_cb		cb;
 };
 
 static void read_config(const char *file)
@@ -84,22 +84,22 @@ static void connect_profile_cb(struct btd_device *device, int err,
 {
 	struct connect_req *req = data;
 
-	req->cb(req->profile, req->device, err);
+	req->cb(req->dp, err);
 
 	g_free(req);
 }
 
-static int connect_profile(struct btd_device *dev, struct btd_profile *profile,
-						uint16_t id, btd_profile_cb cb)
+static int connect_profile(struct btd_device_profile *dp, uint16_t id,
+						btd_device_profile_cb cb)
 {
+	struct btd_device *dev = device_profile_get_device(dp);
 	struct connect_req *req;
 	int err;
 
 	DBG("path %s id %u", device_get_path(dev), id);
 
 	req  = g_new0(struct connect_req, 1);
-	req->device = dev;
-	req->profile = profile;
+	req->dp = dp;
 	req->cb = cb;
 
 	err = connection_connect(dev, BNEP_SVC_PANU, NULL, connect_profile_cb,
@@ -112,10 +112,10 @@ static int connect_profile(struct btd_device *dev, struct btd_profile *profile,
 	return 0;
 }
 
-static int disconnect_profile(struct btd_device *dev,
-						struct btd_profile *profile,
-						uint16_t id, btd_profile_cb cb)
+static int disconnect_profile(struct btd_device_profile *dp, uint16_t id,
+						btd_device_profile_cb cb)
 {
+	struct btd_device *dev = device_profile_get_device(dp);
 	int err;
 
 	DBG("path %s id %u", device_get_path(dev), id);
@@ -125,7 +125,7 @@ static int disconnect_profile(struct btd_device *dev,
 		return err;
 
 	if (cb)
-		cb(profile, dev, 0);
+		cb(dp, 0);
 
 	return 0;
 }
@@ -145,16 +145,15 @@ static void network_remove(struct btd_profile *p, struct btd_device *device)
 	connection_unregister(device);
 }
 
-static int panu_connect(struct btd_device *dev, struct btd_profile *profile,
-							btd_profile_cb cb)
+static int panu_connect(struct btd_device_profile *dp, btd_device_profile_cb cb)
 {
-	return connect_profile(dev, profile, BNEP_SVC_PANU, cb);
+	return connect_profile(dp, BNEP_SVC_PANU, cb);
 }
 
-static int panu_disconnect(struct btd_device *dev, struct btd_profile *profile,
-							btd_profile_cb cb)
+static int panu_disconnect(struct btd_device_profile *dp,
+						btd_device_profile_cb cb)
 {
-	return disconnect_profile(dev, profile, BNEP_SVC_PANU, cb);
+	return disconnect_profile(dp, BNEP_SVC_PANU, cb);
 }
 
 static int panu_server_probe(struct btd_profile *p, struct btd_adapter *adapter)
@@ -184,16 +183,15 @@ static int gn_probe(struct btd_profile *p, struct btd_device *device,
 	return connection_register(device, BNEP_SVC_GN);
 }
 
-static int gn_connect(struct btd_device *dev, struct btd_profile *profile,
-							btd_profile_cb cb)
+static int gn_connect(struct btd_device_profile *dp, btd_device_profile_cb cb)
 {
-	return connect_profile(dev, profile, BNEP_SVC_GN, cb);
+	return connect_profile(dp, BNEP_SVC_GN, cb);
 }
 
-static int gn_disconnect(struct btd_device *dev, struct btd_profile *profile,
-							btd_profile_cb cb)
+static int gn_disconnect(struct btd_device_profile *dp,
+						btd_device_profile_cb cb)
 {
-	return disconnect_profile(dev, profile, BNEP_SVC_GN, cb);
+	return disconnect_profile(dp, BNEP_SVC_GN, cb);
 }
 
 static int gn_server_probe(struct btd_profile *p, struct btd_adapter *adapter)
@@ -223,16 +221,15 @@ static int nap_probe(struct btd_profile *p, struct btd_device *device,
 	return connection_register(device, BNEP_SVC_NAP);
 }
 
-static int nap_connect(struct btd_device *dev, struct btd_profile *profile,
-							btd_profile_cb cb)
+static int nap_connect(struct btd_device_profile *dp, btd_device_profile_cb cb)
 {
-	return connect_profile(dev, profile, BNEP_SVC_NAP, cb);
+	return connect_profile(dp, BNEP_SVC_NAP, cb);
 }
 
-static int nap_disconnect(struct btd_device *dev, struct btd_profile *profile,
-							btd_profile_cb cb)
+static int nap_disconnect(struct btd_device_profile *dp,
+						btd_device_profile_cb cb)
 {
-	return disconnect_profile(dev, profile, BNEP_SVC_NAP, cb);
+	return disconnect_profile(dp, BNEP_SVC_NAP, cb);
 }
 
 static int nap_server_probe(struct btd_profile *p, struct btd_adapter *adapter)
diff --git a/src/device-profile.c b/src/device-profile.c
new file mode 100644
index 0000000..ea796ac
--- /dev/null
+++ b/src/device-profile.c
@@ -0,0 +1,124 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2012  BMW Car IT GmbH
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  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.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/uuid.h>
+#include <bluetooth/sdp.h>
+#include <bluetooth/sdp_lib.h>
+#include <bluetooth/mgmt.h>
+
+#include <glib.h>
+
+#include "log.h"
+
+#include "adapter.h"
+#include "device.h"
+#include "profile.h"
+#include "device-profile.h"
+
+struct btd_device_profile {
+	gint			ref;
+	struct btd_device	*device;
+	struct btd_profile	*profile;
+	profile_state_t		state;
+};
+
+static char *str_state[] = {
+	"PROFILE_STATE_DISCONNECTED",
+	"PROFILE_STATE_CONNECTING",
+	"PROFILE_STATE_CONNECTED",
+};
+
+struct btd_device *device_profile_get_device(struct btd_device_profile *dp)
+{
+	return dp->device;
+}
+
+struct btd_profile *device_profile_get_profile(struct btd_device_profile *dp)
+{
+	return dp->profile;
+}
+
+void device_profile_set_state(struct btd_device_profile *dp,
+							profile_state_t state)
+{
+	DBG("State changed %p: %s -> %s", dp, str_state[dp->state],
+							str_state[state]);
+
+	dp->state = state;
+}
+
+struct btd_device_profile *device_profile_create(struct btd_device *device,
+						struct btd_profile *profile)
+{
+	struct btd_device_profile *dp;
+
+	dp = g_try_new0(struct btd_device_profile, 1);
+	if (!dp) {
+		error("device_profile_create: failed to alloc memory");
+		return NULL;
+	}
+
+	dp->ref = 1;
+	dp->device = btd_device_ref(device);
+	dp->profile = profile;
+	dp->state = PROFILE_STATE_DISCONNECTED;
+
+	return dp;
+}
+
+struct btd_device_profile *device_profile_ref(struct btd_device_profile *dp)
+{
+	dp->ref++;
+
+	DBG("%p: ref=%d", dp, dp->ref);
+
+	return dp;
+}
+
+void device_profile_unref(struct btd_device_profile *dp)
+{
+	dp->ref--;
+
+	DBG("%p: ref=%d", dp, dp->ref);
+
+	if (dp->ref > 0)
+		return;
+
+	btd_device_unref(dp->device);
+
+	g_free(dp);
+}
diff --git a/src/device-profile.h b/src/device-profile.h
new file mode 100644
index 0000000..ef75d79
--- /dev/null
+++ b/src/device-profile.h
@@ -0,0 +1,42 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2012  BMW Car IT GmbH
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  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.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+typedef enum {
+	PROFILE_STATE_DISCONNECTED,
+	PROFILE_STATE_CONNECTING,
+	PROFILE_STATE_CONNECTED,
+} profile_state_t;
+
+struct btd_device_profile;
+
+struct btd_device_profile *device_profile_create(struct btd_device *device,
+						struct btd_profile *profile);
+
+struct btd_device_profile *device_profile_ref(struct btd_device_profile *dp);
+void device_profile_unref(struct btd_device_profile *dp);
+
+struct btd_device *device_profile_get_device(struct btd_device_profile *dp);
+struct btd_profile *device_profile_get_profile(struct btd_device_profile *dp);
+
+void device_profile_set_state(struct btd_device_profile *dp,
+							profile_state_t state);
diff --git a/src/device.c b/src/device.c
index bc7f8dd..37eddef 100644
--- a/src/device.c
+++ b/src/device.c
@@ -54,6 +54,7 @@
 #include "attio.h"
 #include "device.h"
 #include "profile.h"
+#include "device-profile.h"
 #include "dbus-common.h"
 #include "error.h"
 #include "glib-helper.h"
@@ -852,10 +853,14 @@ static gboolean dev_property_get_adapter(const GDBusPropertyTable *property,
 	return TRUE;
 }
 
-static void profile_remove(struct btd_profile *profile,
-						struct btd_device *device)
+static void profile_remove(gpointer p)
 {
+	struct btd_device_profile *dp = p;
+	struct btd_device *device = device_profile_get_device(dp);
+	struct btd_profile *profile = device_profile_get_profile(dp);
+
 	profile->device_remove(profile, device);
+	device_profile_unref(dp);
 }
 
 static gboolean do_disconnect(gpointer user_data)
@@ -880,8 +885,7 @@ int device_block(struct btd_device *device, gboolean update_only)
 	if (device->connected)
 		do_disconnect(device);
 
-	g_slist_foreach(device->profiles, (GFunc) profile_remove, device);
-	g_slist_free(device->profiles);
+	g_slist_free_full(device->profiles, profile_remove);
 	device->profiles = NULL;
 
 	if (!update_only)
@@ -1100,13 +1104,15 @@ static void bonding_request_cancel(struct bonding_req *bonding)
 
 static void dev_disconn_profile(gpointer a, gpointer b)
 {
-	struct btd_profile *profile = a;
-	struct btd_device *dev = b;
+	struct btd_device_profile *dp = a;
+	struct btd_profile *profile = device_profile_get_profile(dp);
 
 	if (!profile->disconnect)
 		return;
 
-	profile->disconnect(dev, profile, NULL);
+	profile->disconnect(dp, NULL);
+
+	device_profile_set_state(dp, PROFILE_STATE_DISCONNECTED);
 }
 
 void device_request_disconnect(struct btd_device *device, DBusMessage *msg)
@@ -1127,7 +1133,7 @@ void device_request_disconnect(struct btd_device *device, DBusMessage *msg)
 		return;
 
 	if (device->profiles_connected)
-		g_slist_foreach(device->profiles, dev_disconn_profile, device);
+		g_slist_foreach(device->profiles, dev_disconn_profile, NULL);
 
 	g_slist_free(device->pending);
 	device->pending = NULL;
@@ -1170,32 +1176,42 @@ static DBusMessage *disconnect(DBusConnection *conn, DBusMessage *msg,
 	return NULL;
 }
 
-static int connect_next(struct btd_device *dev, btd_profile_cb cb)
+static int connect_next(struct btd_device *dev, btd_device_profile_cb cb)
 {
-	struct btd_profile *profile;
 	int err = -ENOENT;
 
 	while (dev->pending) {
+		struct btd_device_profile *dp;
+		struct btd_profile *profile;
 		int err;
 
-		profile = dev->pending->data;
+		dp = dev->pending->data;
+		profile = device_profile_get_profile(dp);
 
-		err = profile->connect(dev, profile, cb);
-		if (err == 0)
+		err = profile->connect(dp, cb);
+		if (err == 0) {
+			device_profile_set_state(dp, PROFILE_STATE_CONNECTING);
 			return 0;
+		}
 
 		error("Failed to connect %s: %s", profile->name,
 							strerror(-err));
-		dev->pending = g_slist_remove(dev->pending, profile);
+		dev->pending = g_slist_remove_link(dev->pending, dev->pending);
 	}
 
 	return err;
 }
 
-static void dev_profile_connected(struct btd_profile *profile,
-					struct btd_device *dev, int err)
+static void dev_profile_connected(struct btd_device_profile *dp, int err)
 {
-	dev->pending = g_slist_remove(dev->pending, profile);
+	struct btd_device *dev = device_profile_get_device(dp);
+
+	dev->pending = g_slist_remove(dev->pending, dp);
+
+	if (err == 0)
+		device_profile_set_state(dp, PROFILE_STATE_CONNECTED);
+	else
+		device_profile_set_state(dp, PROFILE_STATE_DISCONNECTED);
 
 	if (connect_next(dev, dev_profile_connected) == 0)
 		return;
@@ -1245,7 +1261,7 @@ static DBusMessage *dev_connect(DBusConnection *conn, DBusMessage *msg,
 							void *user_data)
 {
 	struct btd_device *dev = user_data;
-	struct btd_profile *p;
+	struct btd_device_profile *dp;
 	GSList *l;
 	int err;
 
@@ -1265,7 +1281,10 @@ static DBusMessage *dev_connect(DBusConnection *conn, DBusMessage *msg,
 	}
 
 	for (l = dev->profiles; l != NULL; l = g_slist_next(l)) {
-		p = l->data;
+		struct btd_profile *p;
+
+		dp = l->data;
+		p = device_profile_get_profile(dp);
 
 		if (p->auto_connect)
 			dev->pending = g_slist_append(dev->pending, p);
@@ -1731,7 +1750,7 @@ void device_remove(struct btd_device *device, gboolean remove_stored)
 	}
 
 	if (device->profiles_connected)
-		g_slist_foreach(device->profiles, dev_disconn_profile, device);
+		g_slist_foreach(device->profiles, dev_disconn_profile, NULL);
 
 	g_slist_free(device->pending);
 	device->pending = NULL;
@@ -1742,8 +1761,7 @@ void device_remove(struct btd_device *device, gboolean remove_stored)
 	if (remove_stored)
 		device_remove_stored(device);
 
-	g_slist_foreach(device->profiles, (GFunc) profile_remove, device);
-	g_slist_free(device->profiles);
+	g_slist_free_full(device->profiles, profile_remove);
 	device->profiles = NULL;
 
 	attrib_client_unregister(device->services);
@@ -1820,6 +1838,7 @@ struct probe_data {
 static void dev_probe(struct btd_profile *p, void *user_data)
 {
 	struct probe_data *d = user_data;
+	struct btd_device_profile *dp;
 	GSList *probe_uuids;
 	int err;
 
@@ -1837,7 +1856,9 @@ static void dev_probe(struct btd_profile *p, void *user_data)
 		return;
 	}
 
-	d->dev->profiles = g_slist_append(d->dev->profiles, p);
+	dp = device_profile_create(d->dev, p);
+
+	d->dev->profiles = g_slist_append(d->dev->profiles, dp);
 	g_slist_free(probe_uuids);
 }
 
@@ -1845,6 +1866,7 @@ void device_probe_profile(gpointer a, gpointer b)
 {
 	struct btd_device *device = a;
 	struct btd_profile *profile = b;
+	struct btd_device_profile *dp;
 	GSList *probe_uuids;
 	char addr[18];
 	int err;
@@ -1859,23 +1881,45 @@ void device_probe_profile(gpointer a, gpointer b)
 	ba2str(&device->bdaddr, addr);
 
 	err = profile->device_probe(profile, device, probe_uuids);
-	if (err < 0)
+	if (err < 0) {
 		error("%s profile probe failed for %s", profile->name, addr);
-	else
-		device->profiles = g_slist_append(device->profiles, profile);
+		g_slist_free(probe_uuids);
+		return;
+	}
+
+	dp = device_profile_create(device, profile);
 
+	device->profiles = g_slist_append(device->profiles, dp);
 	g_slist_free(probe_uuids);
 }
 
+static gint device_profile_cmp(gconstpointer a, gconstpointer b)
+{
+	struct btd_device_profile *dp = (gpointer) a;
+	const struct btd_profile *profile = b;
+
+	if (device_profile_get_profile(dp) == profile)
+		return 0;
+
+	return 1;
+}
+
 void device_remove_profile(gpointer a, gpointer b)
 {
 	struct btd_device *device = a;
 	struct btd_profile *profile = b;
+	struct btd_device_profile *dp;
+	GSList *l;
 
-	if (!g_slist_find(device->profiles, profile))
+	l = g_slist_find_custom(device->profiles, profile, device_profile_cmp);
+	if (l == NULL)
 		return;
 
-	device->profiles = g_slist_remove(device->profiles, profile);
+	dp = l->data;
+
+	device->profiles = g_slist_remove_link(device->profiles, l);
+
+	device_profile_unref(dp);
 
 	profile->device_remove(profile, device);
 }
@@ -1948,7 +1992,8 @@ static void device_remove_profiles(struct btd_device *device, GSList *uuids)
 		sdp_list_free(records, (sdp_free_func_t) sdp_record_free);
 
 	for (l = device->profiles; l != NULL; l = next) {
-		struct btd_profile *profile = l->data;
+		struct btd_device_profile *dp = l->data;
+		struct btd_profile *profile = device_profile_get_profile(dp);
 		GSList *probe_uuids;
 
 		next = l->next;
@@ -1960,7 +2005,9 @@ static void device_remove_profiles(struct btd_device *device, GSList *uuids)
 		}
 
 		profile->device_remove(profile, device);
-		device->profiles = g_slist_remove(device->profiles, profile);
+		device->profiles = g_slist_remove_link(device->profiles, l);
+
+		device_profile_unref(dp);
 	}
 }
 
diff --git a/src/profile.c b/src/profile.c
index 7e7c945..cc78612 100644
--- a/src/profile.c
+++ b/src/profile.c
@@ -50,6 +50,7 @@
 #include "manager.h"
 #include "device.h"
 #include "profile.h"
+#include "device-profile.h"
 
 #define SPP_DEFAULT_CHANNEL	3
 
@@ -88,10 +89,10 @@ struct ext_io {
 	GIOChannel *io;
 	guint io_id;
 	struct btd_adapter *adapter;
-	struct btd_device *device;
+	struct btd_device_profile *dp;
 
 	bool resolving;
-	btd_profile_cb cb;
+	btd_device_profile_cb cb;
 	uint16_t rec_handle;
 
 	guint auth_id;
@@ -185,9 +186,13 @@ static void ext_io_destroy(gpointer p)
 		ext_cancel(ext);
 	}
 
-	if (ext_io->resolving)
+	if (ext_io->resolving) {
+		struct btd_device *device;
+
+		device = device_profile_get_device(ext_io->dp);
 		bt_cancel_discovery(adapter_get_address(ext_io->adapter),
-					device_get_address(ext_io->device));
+						device_get_address(device));
+	}
 
 	if (ext_io->rec_handle)
 		remove_record_from_server(ext_io->rec_handle);
@@ -195,8 +200,8 @@ static void ext_io_destroy(gpointer p)
 	if (ext_io->adapter)
 		btd_adapter_unref(ext_io->adapter);
 
-	if (ext_io->device)
-		btd_device_unref(ext_io->device);
+	if (ext_io->dp)
+		device_profile_unref(ext_io->dp);
 
 	g_free(ext_io);
 }
@@ -244,7 +249,7 @@ static void new_conn_reply(DBusPendingCall *call, void *user_data)
 
 	if (!dbus_error_is_set(&err)) {
 		if (conn->cb) {
-			conn->cb(&ext->p, conn->device, 0);
+			conn->cb(conn->dp, 0);
 			conn->cb = NULL;
 		}
 		return;
@@ -254,7 +259,7 @@ static void new_conn_reply(DBusPendingCall *call, void *user_data)
 						err.name, err.message);
 
 	if (conn->cb) {
-		conn->cb(&ext->p, conn->device, -ECONNREFUSED);
+		conn->cb(conn->dp, -ECONNREFUSED);
 		conn->cb = NULL;
 	}
 
@@ -638,7 +643,7 @@ static void remove_connect(struct ext_profile *ext, struct btd_device *dev)
 		if (!conn->cb)
 			continue;
 
-		if (conn->device != dev)
+		if (device_profile_get_device(conn->dp) != dev)
 			continue;
 
 		ext->conns = g_slist_remove(ext->conns, conn);
@@ -716,6 +721,7 @@ static uint16_t get_goep_l2cap_psm(sdp_record_t *rec)
 static void record_cb(sdp_list_t *recs, int err, gpointer user_data)
 {
 	struct ext_io *conn = user_data;
+	struct btd_device *device = device_profile_get_device(conn->dp);
 	struct ext_profile *ext = conn->ext;
 	sdp_list_t *r;
 
@@ -769,7 +775,7 @@ static void record_cb(sdp_list_t *recs, int err, gpointer user_data)
 	}
 
 	err = connect_io(conn, adapter_get_address(conn->adapter),
-					device_get_address(conn->device));
+						device_get_address(device));
 	if (err < 0) {
 		error("Connecting %s failed: %s", ext->name, strerror(-err));
 		goto failed;
@@ -778,7 +784,7 @@ static void record_cb(sdp_list_t *recs, int err, gpointer user_data)
 	return;
 
 failed:
-	conn->cb(&ext->p, conn->device, err);
+	conn->cb(conn->dp, err);
 	ext->conns = g_slist_remove(ext->conns, conn);
 	ext_io_destroy(conn);
 }
@@ -799,10 +805,12 @@ static int resolve_service(struct ext_io *conn, const bdaddr_t *src,
 	return err;
 }
 
-static int ext_connect_dev(struct btd_device *dev, struct btd_profile *profile,
-							btd_profile_cb cb)
+static int ext_connect_dev(struct btd_device_profile *dp,
+						btd_device_profile_cb cb)
 {
 	struct btd_adapter *adapter;
+	struct btd_device *dev = device_profile_get_device(dp);
+	struct btd_profile *profile = device_profile_get_profile(dp);
 	struct ext_io *conn;
 	struct ext_profile *ext;
 	int err;
@@ -827,7 +835,7 @@ static int ext_connect_dev(struct btd_device *dev, struct btd_profile *profile,
 		goto failed;
 
 	conn->adapter = btd_adapter_ref(adapter);
-	conn->device = btd_device_ref(dev);
+	conn->dp = device_profile_ref(dp);
 	conn->cb = cb;
 
 	ext->conns = g_slist_append(ext->conns, conn);
@@ -839,17 +847,16 @@ failed:
 	return err;
 }
 
-static int ext_disconnect_dev(struct btd_device *dev,
-						struct btd_profile *profile,
-						btd_profile_cb cb)
+static int ext_disconnect_dev(struct btd_device_profile *dp,
+						btd_device_profile_cb cb)
 {
 	struct ext_profile *ext;
 
-	ext = find_ext(profile);
+	ext = find_ext(device_profile_get_profile(dp));
 	if (!ext)
 		return -ENOENT;
 
-	remove_connect(ext, dev);
+	remove_connect(ext, device_profile_get_device(dp));
 
 	return 0;
 }
diff --git a/src/profile.h b/src/profile.h
index e20b383..2ee90a7 100644
--- a/src/profile.h
+++ b/src/profile.h
@@ -24,9 +24,11 @@
 #define BTD_UUIDS(args...) ((const char *[]) { args, NULL } )
 
 struct btd_profile;
+struct btd_device_profile;
 
 typedef void (*btd_profile_cb)(struct btd_profile *profile,
 					struct btd_device *device, int err);
+typedef void (*btd_device_profile_cb)(struct btd_device_profile *dp, int err);
 
 struct btd_profile {
 	const char *name;
@@ -41,11 +43,10 @@ struct btd_profile {
 	void (*device_remove) (struct btd_profile *p,
 						struct btd_device *device);
 
-	int (*connect) (struct btd_device *device, struct btd_profile *profile,
-							btd_profile_cb cb);
-	int (*disconnect) (struct btd_device *device,
-						struct btd_profile *profile,
-						btd_profile_cb cb);
+	int (*connect) (struct btd_device_profile *dp,
+						btd_device_profile_cb cb);
+	int (*disconnect) (struct btd_device_profile *dp,
+						btd_device_profile_cb cb);
 
 	int (*adapter_probe) (struct btd_profile *p,
 						struct btd_adapter *adapter);
-- 
1.7.11.7


^ permalink raw reply related

* [RFC v0 13/15] profile: Rename org.bluez.Profile->ProfileAgent
From: Mikel Astiz @ 2012-10-19 15:39 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Mikel Astiz
In-Reply-To: <1350661172-18125-1-git-send-email-mikel.astiz.oss@gmail.com>

From: Mikel Astiz <mikel.astiz@bmw-carit.de>

The interface represents an external component supporting a specific
profile by implementing an agent. Therefore ProfileAgent is a more
accurate name for the D-Bus interface.
---
 doc/manager-api.txt      |  3 ++-
 doc/profile-api.txt      | 53 ------------------------------------------------
 doc/profileagent-api.txt | 53 ++++++++++++++++++++++++++++++++++++++++++++++++
 src/bluetooth.conf       |  2 +-
 src/manager.c            |  2 +-
 src/profile.c            | 11 +++++-----
 test/test-profile        |  8 ++++----
 7 files changed, 67 insertions(+), 65 deletions(-)
 delete mode 100644 doc/profile-api.txt
 create mode 100644 doc/profileagent-api.txt

diff --git a/doc/manager-api.txt b/doc/manager-api.txt
index fe50556..16fe4ee 100644
--- a/doc/manager-api.txt
+++ b/doc/manager-api.txt
@@ -29,7 +29,8 @@ Object path	/
 			Possible errors: org.bluez.Error.InvalidArguments
 					 org.bluez.Error.NoSuchAdapter
 
-		void RegisterProfile(object profile, string uuid, dict options)
+		void RegisterProfileAgent(object profile, string uuid,
+								dict options)
 
 			This registers a profile implementation.
 
diff --git a/doc/profile-api.txt b/doc/profile-api.txt
deleted file mode 100644
index 639202f..0000000
--- a/doc/profile-api.txt
+++ /dev/null
@@ -1,53 +0,0 @@
-BlueZ D-Bus Profile API description
-***********************************
-
-Copyright (C) 2012  Intel Corporation. All rights reserved.
-
-
-Profile hierarchy
-=================
-
-Service		unique name
-Interface	org.bluez.Profile
-Object path	freely definable
-
-Methods		void Release()
-
-			This method gets called when the service daemon
-			unregisters the profile. A profile can use it to do
-			cleanup tasks. There is no need to unregister the
-			profile, because when this method gets called it has
-			already been unregistered.
-
-		void NewConnection(object device, fd)
-
-			This method gets called when a new service level
-			connection has been made and authorized.
-
-			Possible errors: org.bluez.Error.Rejected
-			                 org.bluez.Error.Canceled
-
-		void RequestDisconnection(object device)
-
-			This method gets called when a profile gets
-			disconnected.
-
-			The file descriptor is no longer owned by the service
-			daemon and the profile implementation needs to take
-			care of cleaning up all connections.
-
-			If multiple file descriptors are indicated via
-			NewConnection, it is expected that all of them
-			are disconnected before returning from this
-			method call.
-
-			Possible errors: org.bluez.Error.Rejected
-			                 org.bluez.Error.Canceled
-
-		void Cancel()
-
-			This method gets called to indicate that the profile
-			request failed before a reply was returned.
-
-			All request are queued and there will be only one
-			pending pequest at a time per profile.
diff --git a/doc/profileagent-api.txt b/doc/profileagent-api.txt
new file mode 100644
index 0000000..8a27a01
--- /dev/null
+++ b/doc/profileagent-api.txt
@@ -0,0 +1,53 @@
+BlueZ D-Bus Profile API description
+***********************************
+
+Copyright (C) 2012  Intel Corporation. All rights reserved.
+
+
+Profile hierarchy
+=================
+
+Service		unique name
+Interface	org.bluez.ProfileAgent
+Object path	freely definable
+
+Methods		void Release()
+
+			This method gets called when the service daemon
+			unregisters the profile. A profile can use it to do
+			cleanup tasks. There is no need to unregister the
+			profile, because when this method gets called it has
+			already been unregistered.
+
+		void NewConnection(object device, fd)
+
+			This method gets called when a new service level
+			connection has been made and authorized.
+
+			Possible errors: org.bluez.Error.Rejected
+			                 org.bluez.Error.Canceled
+
+		void RequestDisconnection(object device)
+
+			This method gets called when a profile gets
+			disconnected.
+
+			The file descriptor is no longer owned by the service
+			daemon and the profile implementation needs to take
+			care of cleaning up all connections.
+
+			If multiple file descriptors are indicated via
+			NewConnection, it is expected that all of them
+			are disconnected before returning from this
+			method call.
+
+			Possible errors: org.bluez.Error.Rejected
+			                 org.bluez.Error.Canceled
+
+		void Cancel()
+
+			This method gets called to indicate that the profile
+			request failed before a reply was returned.
+
+			All request are queued and there will be only one
+			pending pequest at a time per profile.
diff --git a/src/bluetooth.conf b/src/bluetooth.conf
index 2db43d9..49dafc8 100644
--- a/src/bluetooth.conf
+++ b/src/bluetooth.conf
@@ -17,7 +17,7 @@
     <allow send_interface="org.bluez.Watcher"/>
     <allow send_interface="org.bluez.ThermometerWatcher"/>
     <allow send_interface="org.bluez.AlertAgent"/>
-    <allow send_interface="org.bluez.Profile"/>
+    <allow send_interface="org.bluez.ProfileAgent"/>
     <allow send_interface="org.bluez.HeartRateWatcher"/>
   </policy>
 
diff --git a/src/manager.c b/src/manager.c
index a96115b..1dc1c54 100644
--- a/src/manager.c
+++ b/src/manager.c
@@ -163,7 +163,7 @@ static const GDBusMethodTable manager_methods[] = {
 			GDBUS_ARGS({ "pattern", "s" }),
 			GDBUS_ARGS({ "adapter", "o" }),
 			find_adapter) },
-	{ GDBUS_METHOD("RegisterProfile",
+	{ GDBUS_METHOD("RegisterProfileAgent",
 			GDBUS_ARGS({ "profile", "o"}, { "UUID", "s" },
 						{ "options", "a{sv}" }),
 			NULL, btd_profile_reg_ext) },
diff --git a/src/profile.c b/src/profile.c
index eb63e1e..7e7c945 100644
--- a/src/profile.c
+++ b/src/profile.c
@@ -157,7 +157,8 @@ static void ext_cancel(struct ext_profile *ext)
 	DBusMessage *msg;
 
 	msg = dbus_message_new_method_call(ext->owner, ext->path,
-						"org.bluez.Profile", "Cancel");
+						"org.bluez.ProfileAgent",
+						"Cancel");
 	if (msg)
 		g_dbus_send_message(btd_get_dbus_connection(), msg);
 }
@@ -274,8 +275,8 @@ static bool send_new_connection(struct ext_profile *ext, struct ext_io *conn,
 	int fd;
 
 	msg = dbus_message_new_method_call(ext->owner, ext->path,
-							"org.bluez.Profile",
-							"NewConnection");
+						"org.bluez.ProfileAgent",
+						"NewConnection");
 	if (!msg) {
 		error("Unable to create NewConnection call for %s", ext->name);
 		return false;
@@ -1108,8 +1109,8 @@ void btd_profile_cleanup(void)
 		ext->conns = NULL;
 
 		msg = dbus_message_new_method_call(ext->owner, ext->path,
-							"org.bluez.Profile",
-							"Release");
+						"org.bluez.ProfileAgent",
+						"Release");
 		if (msg)
 			g_dbus_send_message(conn, msg);
 
diff --git a/test/test-profile b/test/test-profile
index 2d66444..cfc9331 100755
--- a/test/test-profile
+++ b/test/test-profile
@@ -12,18 +12,18 @@ import dbus.mainloop.glib
 from optparse import OptionParser, make_option
 
 class Profile(dbus.service.Object):
-	@dbus.service.method("org.bluez.Profile",
+	@dbus.service.method("org.bluez.ProfileAgent",
 					in_signature="", out_signature="")
 	def Release(self):
 		print("Release")
 		mainloop.quit()
 
-	@dbus.service.method("org.bluez.Profile",
+	@dbus.service.method("org.bluez.ProfileAgent",
 					in_signature="", out_signature="")
 	def Cancel(self):
 		print("Cancel")
 
-	@dbus.service.method("org.bluez.Profile",
+	@dbus.service.method("org.bluez.ProfileAgent",
 					in_signature="oh", out_signature="")
 	def NewConnection(self, path, fd):
 		fd = fd.take()
@@ -84,6 +84,6 @@ if __name__ == '__main__':
 	if (options.channel):
 		opts["Channel"] = dbus.UInt16(options.channel)
 
-	manager.RegisterProfile(options.path, options.uuid, opts)
+	manager.RegisterProfileAgent(options.path, options.uuid, opts)
 
 	mainloop.run()
-- 
1.7.11.7


^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox