Linux bluetooth development
 help / color / mirror / Atom feed
* Re: [PATCH 4/6] Bluetooth: Refactor UUID-16 list generation into its own function
From: Anderson Lizardo @ 2013-01-24 20:25 UTC (permalink / raw)
  To: Johan Hedberg; +Cc: linux-bluetooth
In-Reply-To: <CAJdJm_OMiH4vcoQSG1x++_G_nnQiTseb-moF8p=9k2utE=gAEg@mail.gmail.com>

On Thu, Jan 24, 2013 at 4:21 PM, Anderson Lizardo
<anderson.lizardo@openbossa.org> wrote:
> Hi Johan,
>
> On Thu, Jan 24, 2013 at 3:03 PM, Johan Hedberg <johan.hedberg@gmail.com> wrote:
>> +static u8 *create_uuid16_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
>> +{
>> +       u8 *ptr = data, *uuids_start = NULL;
>> +       struct bt_uuid *uuid;
>
> Maybe you should check for "len < 2" here?

Actually, "len < 4", to be able to fit at least a 16-bit UUID.

-- 
Anderson Lizardo
Instituto Nokia de Tecnologia - INdT
Manaus - Brazil

^ permalink raw reply

* Re: [PATCH 4/6] Bluetooth: Refactor UUID-16 list generation into its own function
From: Anderson Lizardo @ 2013-01-24 20:21 UTC (permalink / raw)
  To: Johan Hedberg; +Cc: linux-bluetooth
In-Reply-To: <1359054206-19528-5-git-send-email-johan.hedberg@gmail.com>

Hi Johan,

On Thu, Jan 24, 2013 at 3:03 PM, Johan Hedberg <johan.hedberg@gmail.com> wrote:
> +static u8 *create_uuid16_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
> +{
> +       u8 *ptr = data, *uuids_start = NULL;
> +       struct bt_uuid *uuid;

Maybe you should check for "len < 2" here?

> +
> +       list_for_each_entry(uuid, &hdev->uuid16, list) {
> +               u16 uuid16;
> +
> +               uuid16 = get_unaligned_le16(&uuid->uuid[12]);
> +               if (uuid16 < 0x1100)
> +                       continue;
> +
> +               if (uuid16 == PNP_INFO_SVCLASS_ID)
> +                       continue;
> +
> +               if (!uuids_start) {
> +                       uuids_start = ptr;
> +                       uuids_start[0] = 1;
> +                       uuids_start[1] = EIR_UUID16_ALL;
> +                       ptr += 2;
> +               }
> +
> +               /* Stop if not enough space to put next UUID */
> +               if ((ptr - data) + sizeof(u16) > len) {
> +                       uuids_start[1] = EIR_UUID16_SOME;
> +                       break;
> +               }
> +
> +               *ptr++ = (uuid16 & 0x00ff);
> +               *ptr++ = (uuid16 & 0xff00) >> 8;
> +               uuids_start[0] += sizeof(uuid16);
> +       }
> +
> +       return ptr;
> +}

Regards,
-- 
Anderson Lizardo
Instituto Nokia de Tecnologia - INdT
Manaus - Brazil

^ permalink raw reply

* [PATCH 6/6] Bluetooth: Add support for 128-bit UUIDs in EIR data
From: Johan Hedberg @ 2013-01-24 19:03 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1359054206-19528-1-git-send-email-johan.hedberg@gmail.com>

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

This patch adds the necessary code for encoding a list of 128-bit UUIDs
into the EIR data.

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

diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index b9310d1..6ca2de1 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -501,6 +501,36 @@ static u8 *create_uuid32_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
 	return ptr;
 }
 
+static u8 *create_uuid128_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
+{
+	u8 *ptr = data, *uuids_start = NULL;
+	struct bt_uuid *uuid;
+
+	if (len < 18)
+		return ptr;
+
+	list_for_each_entry(uuid, &hdev->uuid128, list) {
+		if (!uuids_start) {
+			uuids_start = ptr;
+			uuids_start[0] = 1;
+			uuids_start[1] = EIR_UUID128_ALL;
+			ptr += 2;
+		}
+
+		/* Stop if not enough space to put next UUID */
+		if ((ptr - data) + 16 > len) {
+			uuids_start[1] = EIR_UUID128_SOME;
+			break;
+		}
+
+		memcpy(ptr, uuid->uuid, 16);
+		ptr += 16;
+		uuids_start[0] += 16;
+	}
+
+	return ptr;
+}
+
 static void create_eir(struct hci_dev *hdev, u8 *data)
 {
 	u8 *ptr = data;
@@ -546,6 +576,7 @@ static void create_eir(struct hci_dev *hdev, u8 *data)
 
 	ptr = create_uuid16_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
 	ptr = create_uuid32_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
+	ptr = create_uuid128_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
 }
 
 static int update_eir(struct hci_dev *hdev)
-- 
1.7.10.4


^ permalink raw reply related

* [PATCH 5/6] Bluetooth: Add support for 32-bit UUIDs in EIR data
From: Johan Hedberg @ 2013-01-24 19:03 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1359054206-19528-1-git-send-email-johan.hedberg@gmail.com>

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

This patch adds the necessary code for inserting a list of 32-bit UUIDs
into the EIR data.

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

diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 817d8e8..b9310d1 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -471,6 +471,36 @@ static u8 *create_uuid16_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
 	return ptr;
 }
 
+static u8 *create_uuid32_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
+{
+	u8 *ptr = data, *uuids_start = NULL;
+	struct bt_uuid *uuid;
+
+	if (len < 6)
+		return ptr;
+
+	list_for_each_entry(uuid, &hdev->uuid32, list) {
+		if (!uuids_start) {
+			uuids_start = ptr;
+			uuids_start[0] = 1;
+			uuids_start[1] = EIR_UUID32_ALL;
+			ptr += 2;
+		}
+
+		/* Stop if not enough space to put next UUID */
+		if ((ptr - data) + sizeof(u32) > len) {
+			uuids_start[1] = EIR_UUID32_SOME;
+			break;
+		}
+
+		memcpy(ptr, &uuid->uuid[12], sizeof(u32));
+		ptr += sizeof(u32);
+		uuids_start[0] += sizeof(u32);
+	}
+
+	return ptr;
+}
+
 static void create_eir(struct hci_dev *hdev, u8 *data)
 {
 	u8 *ptr = data;
@@ -515,6 +545,7 @@ static void create_eir(struct hci_dev *hdev, u8 *data)
 	}
 
 	ptr = create_uuid16_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
+	ptr = create_uuid32_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
 }
 
 static int update_eir(struct hci_dev *hdev)
-- 
1.7.10.4


^ permalink raw reply related

* [PATCH 4/6] Bluetooth: Refactor UUID-16 list generation into its own function
From: Johan Hedberg @ 2013-01-24 19:03 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1359054206-19528-1-git-send-email-johan.hedberg@gmail.com>

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

We will need to create three separate UUID lists in the EIR data (for
16, 32 and 128 bit UUIDs) so the code is easier to follow if each list
is generated in their own function.

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

diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 76ba1fd..817d8e8 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -435,11 +435,45 @@ static u32 get_current_settings(struct hci_dev *hdev)
 
 #define PNP_INFO_SVCLASS_ID		0x1200
 
+static u8 *create_uuid16_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
+{
+	u8 *ptr = data, *uuids_start = NULL;
+	struct bt_uuid *uuid;
+
+	list_for_each_entry(uuid, &hdev->uuid16, list) {
+		u16 uuid16;
+
+		uuid16 = get_unaligned_le16(&uuid->uuid[12]);
+		if (uuid16 < 0x1100)
+			continue;
+
+		if (uuid16 == PNP_INFO_SVCLASS_ID)
+			continue;
+
+		if (!uuids_start) {
+			uuids_start = ptr;
+			uuids_start[0] = 1;
+			uuids_start[1] = EIR_UUID16_ALL;
+			ptr += 2;
+		}
+
+		/* Stop if not enough space to put next UUID */
+		if ((ptr - data) + sizeof(u16) > len) {
+			uuids_start[1] = EIR_UUID16_SOME;
+			break;
+		}
+
+		*ptr++ = (uuid16 & 0x00ff);
+		*ptr++ = (uuid16 & 0xff00) >> 8;
+		uuids_start[0] += sizeof(uuid16);
+	}
+
+	return ptr;
+}
+
 static void create_eir(struct hci_dev *hdev, u8 *data)
 {
 	u8 *ptr = data;
-	u8 *uuids_start;
-	struct bt_uuid *uuid;
 	size_t name_len;
 
 	name_len = strlen(hdev->dev_name);
@@ -480,36 +514,7 @@ static void create_eir(struct hci_dev *hdev, u8 *data)
 		ptr += 10;
 	}
 
-	uuids_start = NULL;
-
-	/* Group all UUID16 types */
-	list_for_each_entry(uuid, &hdev->uuid16, list) {
-		u16 uuid16;
-
-		uuid16 = get_unaligned_le16(&uuid->uuid[12]);
-		if (uuid16 < 0x1100)
-			continue;
-
-		if (uuid16 == PNP_INFO_SVCLASS_ID)
-			continue;
-
-		if (!uuids_start) {
-			uuids_start = ptr;
-			uuids_start[0] = 1;
-			uuids_start[1] = EIR_UUID16_ALL;
-			ptr += 2;
-		}
-
-		/* Stop if not enough space to put next UUID */
-		if ((ptr - data) + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) {
-			uuids_start[1] = EIR_UUID16_SOME;
-			break;
-		}
-
-		*ptr++ = (uuid16 & 0x00ff);
-		*ptr++ = (uuid16 & 0xff00) >> 8;
-		uuids_start[0] += sizeof(uuid16);
-	}
+	ptr = create_uuid16_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
 }
 
 static int update_eir(struct hci_dev *hdev)
-- 
1.7.10.4


^ permalink raw reply related

* [PATCH 3/6] Bluetooth: Remove useless eir_len variable from EIR creation
From: Johan Hedberg @ 2013-01-24 19:03 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1359054206-19528-1-git-send-email-johan.hedberg@gmail.com>

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

The amount of data encoded so far in the create_eir() function can be
calculated simply through the difference between the data and ptr
pointer variables. The eir_len variable then becomes essentially
useless.

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

diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index d4e5313..76ba1fd 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -439,7 +439,6 @@ static void create_eir(struct hci_dev *hdev, u8 *data)
 {
 	u8 *ptr = data;
 	u8 *uuids_start;
-	u16 eir_len = 0;
 	struct bt_uuid *uuid;
 	size_t name_len;
 
@@ -458,7 +457,6 @@ static void create_eir(struct hci_dev *hdev, u8 *data)
 
 		memcpy(ptr + 2, hdev->dev_name, name_len);
 
-		eir_len += (name_len + 2);
 		ptr += (name_len + 2);
 	}
 
@@ -467,7 +465,6 @@ static void create_eir(struct hci_dev *hdev, u8 *data)
 		ptr[1] = EIR_TX_POWER;
 		ptr[2] = (u8) hdev->inq_tx_power;
 
-		eir_len += 3;
 		ptr += 3;
 	}
 
@@ -480,7 +477,6 @@ static void create_eir(struct hci_dev *hdev, u8 *data)
 		put_unaligned_le16(hdev->devid_product, ptr + 6);
 		put_unaligned_le16(hdev->devid_version, ptr + 8);
 
-		eir_len += 10;
 		ptr += 10;
 	}
 
@@ -502,18 +498,16 @@ static void create_eir(struct hci_dev *hdev, u8 *data)
 			uuids_start[0] = 1;
 			uuids_start[1] = EIR_UUID16_ALL;
 			ptr += 2;
-			eir_len += 2;
 		}
 
 		/* Stop if not enough space to put next UUID */
-		if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) {
+		if ((ptr - data) + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) {
 			uuids_start[1] = EIR_UUID16_SOME;
 			break;
 		}
 
 		*ptr++ = (uuid16 & 0x00ff);
 		*ptr++ = (uuid16 & 0xff00) >> 8;
-		eir_len += sizeof(uuid16);
 		uuids_start[0] += sizeof(uuid16);
 	}
 }
-- 
1.7.10.4


^ permalink raw reply related

* [PATCH 2/6] Bluetooth: Simplify UUID16 list generation for EIR
From: Johan Hedberg @ 2013-01-24 19:03 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1359054206-19528-1-git-send-email-johan.hedberg@gmail.com>

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

There's no need to use two separate loops to generate a UUID list for
the EIR data. This patch merges the two loops previously used for the
16-bit UUID list generation into a single loop, thus simplifying the
code a great deal.

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

diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 878b4a2..d4e5313 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -438,9 +438,8 @@ static u32 get_current_settings(struct hci_dev *hdev)
 static void create_eir(struct hci_dev *hdev, u8 *data)
 {
 	u8 *ptr = data;
+	u8 *uuids_start;
 	u16 eir_len = 0;
-	u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)];
-	int i, truncated = 0;
 	struct bt_uuid *uuid;
 	size_t name_len;
 
@@ -485,7 +484,7 @@ static void create_eir(struct hci_dev *hdev, u8 *data)
 		ptr += 10;
 	}
 
-	memset(uuid16_list, 0, sizeof(uuid16_list));
+	uuids_start = NULL;
 
 	/* Group all UUID16 types */
 	list_for_each_entry(uuid, &hdev->uuid16, list) {
@@ -498,39 +497,24 @@ static void create_eir(struct hci_dev *hdev, u8 *data)
 		if (uuid16 == PNP_INFO_SVCLASS_ID)
 			continue;
 
+		if (!uuids_start) {
+			uuids_start = ptr;
+			uuids_start[0] = 1;
+			uuids_start[1] = EIR_UUID16_ALL;
+			ptr += 2;
+			eir_len += 2;
+		}
+
 		/* Stop if not enough space to put next UUID */
 		if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) {
-			truncated = 1;
+			uuids_start[1] = EIR_UUID16_SOME;
 			break;
 		}
 
-		/* Check for duplicates */
-		for (i = 0; uuid16_list[i] != 0; i++)
-			if (uuid16_list[i] == uuid16)
-				break;
-
-		if (uuid16_list[i] == 0) {
-			uuid16_list[i] = uuid16;
-			eir_len += sizeof(u16);
-		}
-	}
-
-	if (uuid16_list[0] != 0) {
-		u8 *length = ptr;
-
-		/* EIR Data type */
-		ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL;
-
-		ptr += 2;
-		eir_len += 2;
-
-		for (i = 0; uuid16_list[i] != 0; i++) {
-			*ptr++ = (uuid16_list[i] & 0x00ff);
-			*ptr++ = (uuid16_list[i] & 0xff00) >> 8;
-		}
-
-		/* EIR Data length */
-		*length = (i * sizeof(u16)) + 1;
+		*ptr++ = (uuid16 & 0x00ff);
+		*ptr++ = (uuid16 & 0xff00) >> 8;
+		eir_len += sizeof(uuid16);
+		uuids_start[0] += sizeof(uuid16);
 	}
 }
 
-- 
1.7.10.4


^ permalink raw reply related

* [PATCH 1/6] Bluetooth: Split UUIDs to three separate lists
From: Johan Hedberg @ 2013-01-24 19:03 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1359054206-19528-1-git-send-email-johan.hedberg@gmail.com>

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

The primary purpose of the UUIDs is to eable generation of EIR and AD
data. In these data formats the UUIDs are split into separate fields
based on whether they're 16, 32 or 128 bit UUIDs. To make the generation
of these data fields simple this patch splits the UUIDs into three
separate lists based on their type.

To keep cases needing access to all UUIDs easy the UUIDs are also kept
in an "all" list. This is particularly useful for exposing the UUIDs
through sysfs as well as removing UUIDs (whether removing a specific one
or all UUIDs).

Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
---
 include/net/bluetooth/hci_core.h |    4 ++
 net/bluetooth/hci_core.c         |   14 +++----
 net/bluetooth/hci_sysfs.c        |    2 +-
 net/bluetooth/mgmt.c             |   85 +++++++++++++++++++++++---------------
 4 files changed, 63 insertions(+), 42 deletions(-)

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index bcf8ffe..d3b1d1b 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -85,6 +85,7 @@ struct bdaddr_list {
 
 struct bt_uuid {
 	struct list_head list;
+	struct list_head all;
 	u8 uuid[16];
 	u8 svc_hint;
 };
@@ -256,6 +257,9 @@ struct hci_dev {
 	struct list_head	blacklist;
 
 	struct list_head	uuids;
+	struct list_head	uuid16;
+	struct list_head	uuid32;
+	struct list_head	uuid128;
 
 	struct list_head	link_keys;
 
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index e061b35..8818521 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -1183,14 +1183,11 @@ static void hci_discov_off(struct work_struct *work)
 
 int hci_uuids_clear(struct hci_dev *hdev)
 {
-	struct list_head *p, *n;
-
-	list_for_each_safe(p, n, &hdev->uuids) {
-		struct bt_uuid *uuid;
+	struct bt_uuid *uuid, *tmp;
 
-		uuid = list_entry(p, struct bt_uuid, list);
-
-		list_del(p);
+	list_for_each_entry_safe(uuid, tmp, &hdev->uuids, all) {
+		list_del(&uuid->list);
+		list_del(&uuid->all);
 		kfree(uuid);
 	}
 
@@ -1718,6 +1715,9 @@ struct hci_dev *hci_alloc_dev(void)
 	INIT_LIST_HEAD(&hdev->mgmt_pending);
 	INIT_LIST_HEAD(&hdev->blacklist);
 	INIT_LIST_HEAD(&hdev->uuids);
+	INIT_LIST_HEAD(&hdev->uuid16);
+	INIT_LIST_HEAD(&hdev->uuid32);
+	INIT_LIST_HEAD(&hdev->uuid128);
 	INIT_LIST_HEAD(&hdev->link_keys);
 	INIT_LIST_HEAD(&hdev->long_term_keys);
 	INIT_LIST_HEAD(&hdev->remote_oob_data);
diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c
index 23b4e24..9a60c74 100644
--- a/net/bluetooth/hci_sysfs.c
+++ b/net/bluetooth/hci_sysfs.c
@@ -483,7 +483,7 @@ static int uuids_show(struct seq_file *f, void *p)
 
 	hci_dev_lock(hdev);
 
-	list_for_each_entry(uuid, &hdev->uuids, list)
+	list_for_each_entry(uuid, &hdev->uuids, all)
 		print_bt_uuid(f, uuid->uuid);
 
 	hci_dev_unlock(hdev);
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index e7f944f..878b4a2 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -435,28 +435,6 @@ static u32 get_current_settings(struct hci_dev *hdev)
 
 #define PNP_INFO_SVCLASS_ID		0x1200
 
-static u8 bluetooth_base_uuid[] = {
-			0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
-			0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-};
-
-static u16 get_uuid16(u8 *uuid128)
-{
-	u32 val;
-	int i;
-
-	for (i = 0; i < 12; i++) {
-		if (bluetooth_base_uuid[i] != uuid128[i])
-			return 0;
-	}
-
-	val = get_unaligned_le32(&uuid128[12]);
-	if (val > 0xffff)
-		return 0;
-
-	return (u16) val;
-}
-
 static void create_eir(struct hci_dev *hdev, u8 *data)
 {
 	u8 *ptr = data;
@@ -510,13 +488,10 @@ static void create_eir(struct hci_dev *hdev, u8 *data)
 	memset(uuid16_list, 0, sizeof(uuid16_list));
 
 	/* Group all UUID16 types */
-	list_for_each_entry(uuid, &hdev->uuids, list) {
+	list_for_each_entry(uuid, &hdev->uuid16, list) {
 		u16 uuid16;
 
-		uuid16 = get_uuid16(uuid->uuid);
-		if (uuid16 == 0)
-			return;
-
+		uuid16 = get_unaligned_le16(&uuid->uuid[12]);
 		if (uuid16 < 0x1100)
 			continue;
 
@@ -592,7 +567,7 @@ static u8 get_service_classes(struct hci_dev *hdev)
 	struct bt_uuid *uuid;
 	u8 val = 0;
 
-	list_for_each_entry(uuid, &hdev->uuids, list)
+	list_for_each_entry(uuid, &hdev->uuids, all)
 		val |= uuid->svc_hint;
 
 	return val;
@@ -1304,6 +1279,34 @@ unlock:
 	return err;
 }
 
+enum bt_uuid_t {
+	BT_UUID16,
+	BT_UUID32,
+	BT_UUID128,
+};
+
+static u8 bluetooth_base_uuid[] = {
+			0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
+			0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+static enum bt_uuid_t bt_uuid_type(u8 *uuid)
+{
+	u32 val;
+	int i;
+
+	for (i = 0; i < 12; i++) {
+		if (bluetooth_base_uuid[i] != uuid[i])
+			return BT_UUID128;
+	}
+
+	val = get_unaligned_le32(&uuid[12]);
+	if (val > 0xffff)
+		return BT_UUID32;
+
+	return BT_UUID16;
+}
+
 static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
 {
 	struct mgmt_cp_add_uuid *cp = data;
@@ -1330,7 +1333,23 @@ static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
 	memcpy(uuid->uuid, cp->uuid, 16);
 	uuid->svc_hint = cp->svc_hint;
 
-	list_add(&uuid->list, &hdev->uuids);
+	switch (bt_uuid_type(uuid->uuid)) {
+	case BT_UUID16:
+		list_add_tail(&uuid->list, &hdev->uuid16);
+		break;
+	case BT_UUID32:
+		list_add_tail(&uuid->list, &hdev->uuid32);
+		break;
+	case BT_UUID128:
+		list_add_tail(&uuid->list, &hdev->uuid128);
+		break;
+	default:
+		/* Should never be reached */
+		err = -EINVAL;
+		goto failed;
+	}
+
+	list_add_tail(&uuid->all, &hdev->uuids);
 
 	err = update_class(hdev);
 	if (err < 0)
@@ -1374,7 +1393,7 @@ static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
 {
 	struct mgmt_cp_remove_uuid *cp = data;
 	struct pending_cmd *cmd;
-	struct list_head *p, *n;
+	struct bt_uuid *match, *tmp;
 	u8 bt_uuid_any[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
 	int err, found;
 
@@ -1402,13 +1421,11 @@ static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
 
 	found = 0;
 
-	list_for_each_safe(p, n, &hdev->uuids) {
-		struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
-
+	list_for_each_entry_safe(match, tmp, &hdev->uuids, all) {
 		if (memcmp(match->uuid, cp->uuid, 16) != 0)
 			continue;
-
 		list_del(&match->list);
+		list_del(&match->all);
 		kfree(match);
 		found++;
 	}
-- 
1.7.10.4


^ permalink raw reply related

* [PATCH 0/6] Bluetooth: Add 32 and 128 bit EIR UUID support
From: Johan Hedberg @ 2013-01-24 19:03 UTC (permalink / raw)
  To: linux-bluetooth

Hi,

There was another set of patches from Syam to add the same functionality
but it can be accomplished in a simpler way since we only need to follow
the ordering within each group of UUIDs.

I've added test cases to mgmt-tester to verify both the complete and
partial UUID list cases (more can be added, but there are enough that
I'm confident of the correctness of these patches).

Johan Hedberg (6):
      Bluetooth: Split UUIDs to three separate lists
      Bluetooth: Simplify UUID16 list generation for EIR
      Bluetooth: Remove useless eir_len variable from EIR creation
      Bluetooth: Refactor UUID-16 list generation into its own function
      Bluetooth: Add support for 32-bit UUIDs in EIR data
      Bluetooth: Add support for 128-bit UUIDs in EIR data

 include/net/bluetooth/hci_core.h |    4 ++
 net/bluetooth/hci_core.c         |   14 ++---
 net/bluetooth/hci_sysfs.c        |    2 +-
 net/bluetooth/mgmt.c             |  218 +++++++++++++++++++++++++++++++++++++++++-----------------------
 4 files changed, 152 insertions(+), 86 deletions(-)



^ permalink raw reply

* RFC: Race between hci_unregister_dev and hidp_session
From: Karl Relton @ 2013-01-24 16:44 UTC (permalink / raw)
  To: Gustavo Padovan, Marcel Holtmann; +Cc: linux-bluetooth

Dear Gustavo/Marcel

I believe I have tracked down a race condition between
hci_unregister_dev() and hidp_session() that can lead to userspace
failure of bluetooth input devices (see [1] below).


hci_unregister_dev calls
  hci_dev_do_close calls
    hci_conn_hash_flush calls
      hci_proto_disconn_cfm which triggers (via a wakeup)
        hidp_session running in another thread (a kthread)

hci_unregister_dev, after the above calls, will go on to call
  hci_del_sysfs to remove the 'hci' device

Meanwhile hidp_session will drop out its main loop, start cleaning up
which includes a call to
   hid_destroy_device which removes the input & hid (and hidraw) devices


For correct operation, and what userspace would normally expect, removal
from the sysfs tree should be 'bottom up', i.e. event then input then
hid then hci.

For this operation, one would need to guaruntee that hidp_session
finishes its cleanup before hci_unregister_dev continues with its work.

At the moment this is not done. Any delay in hidp_session will allow
hci_unregister_dev to win the race, causing an out of sequence sysfs
removal, and headaches for userspace.


Currently, the power_supply system is causing hidp_session to stall for
5 seconds (as detailed in [2]). Plenty of time to cause hidp_session to
lose the race! But even without such silliness, a race can't be a good
thing can it?


How to fix? Some synchronisation between hidp_session thread and the hci
code is required. hci_conn devices already use a ref counting system to
delay removing the device from sysfs until the count gets to zero
(hci_conn_put_device), so presumably a similar arrangement can be
implemented for the hci device? Note this would need to be a different
count to that currently in hci_dev_put/hold, because that is based on
the lower level kobj references. Perhaps hci_dev_put/hold can be
augmented to keep its own count in addition to the underlying kobj
count?

Karl


References:
[1] https://bugzilla.kernel.org/show_bug.cgi?id=52471
the udev remove events, being out of sequence, have truncated paths
which disturbs userspace programs like Xorg evdev so they cannot process
the keyboard/mouse removal.

[2] https://bugzilla.kernel.org/show_bug.cgi?id=52471#c2 and
https://bugzilla.kernel.org/show_bug.cgi?id=52471#c3

^ permalink raw reply

* Re: usb device removed from sysfs before input children devices
From: Karl Relton @ 2013-01-24 16:09 UTC (permalink / raw)
  To: linux-usb, linux-bluetooth
In-Reply-To: <1359035887.5482.1.camel@dellpc>

On Thu, 2013-01-24 at 13:58 +0000, Karl Relton wrote:
> On Tue, 2013-01-15 at 20:27 +0000, Karl Relton wrote:
> > > The end result (for the user) is that even when the bluetooth
> > > mouse/keyboard is re-added, Xorg ignores it - thinking it is some
> > hoax
> > > duplicate device. The keyboard/mouse is then non-operational.
> > > 
> > 
> > Instrumenting the code suggests that the issue arises in a race
> > between:
> > 
> > hidp_session() in bluetooth/hidp/core.c
> > 
> > and
> > 
> > hci_unregister_dev() in bluetooth/hci_core.c
> > 
> > 

...

> > 
> > I can't figure out why there is such a delay for
> > input_unregister_device(). 
> 
> 
> The power_supply system seems to be triggering a lookup of battery
> 'capacity' in the input device. This calls into the driver, which deep
> down invokes more code in the 'hidp' module: hidp_get_raw_report()
> 
> This function tries to communicate with the bluetooth device (keyboard
> in my case), but because the device is being 'torn down' such
> communication fails. Accordingly hidp_get_raw_report has a 5 second
> timeout ... so this function stalls for 5 seconds until that timeout
> occurs.
> 
> 
> I would guess that for some reason, removing the 'hid' or associated
> 'input' device is leading to the power_supply code wanting to lookup the
> battery capacity which introduces a 5 second wait. This would delay
> hidp_session by 5 seconds ... in the mean time allowing
> hci_unregister_dev() to win the race and hence the hci device is removed
> before the input & hid devices.
> 

device_del is done on the battery device, called from
hidinput_cleanup_battery in hid-input.c.

This will generate a uevent which has the power_supply attributes added,
which invokes power_supply_show_property for 'capacity' which invokes
the hidp_get_raw_report (which stalls for 5 seconds).


Back in the days of linux 3.2, hid-input.c did not have any support for
batteries, so this chain of calls was never made, hence the race was won
by hidp_session() because it didn't have the 5 second delay injected.

Now with battery support added, the problem is manifest.

--

I think hidp_get_raw_report should abort if the devices is being 'torn
down' (and so not go into the 5 second wait). But also the race between
the two functions needs sorting, since sooner or later someone else will
get unlucky.




^ permalink raw reply

* Re: Query regarding LE encryption failure
From: Anderson Lizardo @ 2013-01-24 14:32 UTC (permalink / raw)
  To: Jaganath Kanakkassery; +Cc: linux-bluetooth
In-Reply-To: <3C2963DE7FB6424B9BCE227143415153@sisodomain.com>

Hi  Jaganath,

On Thu, Jan 24, 2013 at 9:55 AM, Jaganath Kanakkassery
<jaganath.k@samsung.com> wrote:
> Hello,
>
> We are using BlueZ-4.101 and the device is paired with an LE proximity
> device.
> When "DiscoverCharacteristics" is called, after creating LE connection it is
> trying to encrypt the link which fails with "Pin or key missing".
>
> < HCI Command: LE Start Encryption (0x08|0x0019) plen 28
>  0000: 40 00 cb 2e 2a ec a1 c5  3c ad 2d d5 02 dc 91 a5  @...*...<.-.....
>  0010: d7 7b b0 aa 82 ef cb 32  31 ce 4e 6f              .{.....21.No
>>
>> HCI Event: Command Status (0x0f) plen 4
>
>    LE Start Encryption (0x08|0x0019) status 0x00 ncmd 1
>>
>> HCI Event: Encrypt Change (0x08) plen 4
>
>    status 0x06 handle 64 encrypt 0x00
>    Error: PIN or Key Missing
>
> Any idea why it is failing?

It looks to me the remote device lose the bonding. Are you sure it was
not power cycled (i.e. the battery removed or device was reset some
way)?

>
> One thing I noticed is during pairing also this encryption is being done
> and it succeeded.
>
> < HCI Command: LE Start Encryption (0x08|0x0019) plen 28
>  0000: 40 00 00 00 00 00 00 00  00 00 00 00 f4 33 19 ea  @............3..
>  0010: aa 35 95 5a 51 cf 15 a6  23 8a 05 27              .5.ZQ...#..'
>>
>> HCI Event: Command Status (0x0f) plen 4
>
>    LE Start Encryption (0x08|0x0019) status 0x00 ncmd 1
>>
>> HCI Event: Encrypt Change (0x08) plen 4
>
>    status 0x00 handle 64 encrypt 0x01
>
>
> But both the encryption packets are different. Is it expected?

IIRC this should be the STK used for encryption right after "just
works" pairing. See Figure 5.5 from page 2005 of Core spec. It will
not match the LTK used for encryption after re-connection.

Regards,
-- 
Anderson Lizardo
Instituto Nokia de Tecnologia - INdT
Manaus - Brazil

^ permalink raw reply

* Re: usb device removed from sysfs before input children devices
From: Karl Relton @ 2013-01-24 13:58 UTC (permalink / raw)
  To: linux-usb, linux-bluetooth
In-Reply-To: <1358281626.3998.29.camel@dellpc>

On Tue, 2013-01-15 at 20:27 +0000, Karl Relton wrote:
> > The end result (for the user) is that even when the bluetooth
> > mouse/keyboard is re-added, Xorg ignores it - thinking it is some
> hoax
> > duplicate device. The keyboard/mouse is then non-operational.
> > 
> 
> Instrumenting the code suggests that the issue arises in a race
> between:
> 
> hidp_session() in bluetooth/hidp/core.c
> 
> and
> 
> hci_unregister_dev() in bluetooth/hci_core.c
> 
> 
> Basically hci_unregister_dev() does a hci_dev_do_close() which in turn
> shuts down the hidp connection. This causes hidp_session() running in
> another thread to go into its cleanup phase, which is where the input
> children devices are unregistered.
> 
> HOWEVER:
> 1) For some reason input_unregister_device() seems to stall some 3-5
> seconds on my system before removing the input device
> 2) In parallel hci_unregister_dev() ploughs on, and progresses to
> remove
> its hdev (hci<n> device) regardless, without waiting for
> hidp_session()
> to complete.
> 
> I can't figure out why there is such a delay for
> input_unregister_device(). 


The power_supply system seems to be triggering a lookup of battery
'capacity' in the input device. This calls into the driver, which deep
down invokes more code in the 'hidp' module: hidp_get_raw_report()

This function tries to communicate with the bluetooth device (keyboard
in my case), but because the device is being 'torn down' such
communication fails. Accordingly hidp_get_raw_report has a 5 second
timeout ... so this function stalls for 5 seconds until that timeout
occurs.


I would guess that for some reason, removing the 'hid' or associated
'input' device is leading to the power_supply code wanting to lookup the
battery capacity which introduces a 5 second wait. This would delay
hidp_session by 5 seconds ... in the mean time allowing
hci_unregister_dev() to win the race and hence the hci device is removed
before the input & hid devices.



^ permalink raw reply

* Query regarding LE encryption failure
From: Jaganath Kanakkassery @ 2013-01-24 13:55 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1358781718-386-3-git-send-email-luiz.dentz@gmail.com>

Hello,

We are using BlueZ-4.101 and the device is paired with an LE proximity 
device.
When "DiscoverCharacteristics" is called, after creating LE connection it is
trying to encrypt the link which fails with "Pin or key missing".

< HCI Command: LE Start Encryption (0x08|0x0019) plen 28
  0000: 40 00 cb 2e 2a ec a1 c5  3c ad 2d d5 02 dc 91 a5  @...*...<.-.....
  0010: d7 7b b0 aa 82 ef cb 32  31 ce 4e 6f              .{.....21.No
> HCI Event: Command Status (0x0f) plen 4
    LE Start Encryption (0x08|0x0019) status 0x00 ncmd 1
> HCI Event: Encrypt Change (0x08) plen 4
    status 0x06 handle 64 encrypt 0x00
    Error: PIN or Key Missing

Any idea why it is failing?

One thing I noticed is during pairing also this encryption is being done
and it succeeded.

< HCI Command: LE Start Encryption (0x08|0x0019) plen 28
  0000: 40 00 00 00 00 00 00 00  00 00 00 00 f4 33 19 ea  @............3..
  0010: aa 35 95 5a 51 cf 15 a6  23 8a 05 27              .5.ZQ...#..'
> HCI Event: Command Status (0x0f) plen 4
    LE Start Encryption (0x08|0x0019) status 0x00 ncmd 1
> HCI Event: Encrypt Change (0x08) plen 4
    status 0x00 handle 64 encrypt 0x01


But both the encryption packets are different. Is it expected?

Thanks,
Jaganath
 


^ permalink raw reply

* [PATCH BlueZ 6/6 v2] tools: Emit Seeked signal if Position changes
From: Luiz Augusto von Dentz @ 2013-01-24  9:58 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1359021484-6958-1-git-send-email-luiz.dentz@gmail.com>

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

MPRIS spec says PropertiesChanged is not emitted for Position, which is
probably to make clear that progress is done using the rate, so instead
Seeked should be emitted.
---
 tools/mpris-player.c | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/tools/mpris-player.c b/tools/mpris-player.c
index 5903ca1..95ef8ab 100644
--- a/tools/mpris-player.c
+++ b/tools/mpris-player.c
@@ -1650,6 +1650,8 @@ static void player_property_changed(GDBusProxy *proxy, const char *name,
 {
 	struct player *player;
 	const char *property;
+	uint32_t position;
+	uint64_t value;
 
 	player = find_player(proxy);
 	if (player == NULL)
@@ -1662,6 +1664,18 @@ static void player_property_changed(GDBusProxy *proxy, const char *name,
 	g_dbus_emit_property_changed(player->conn, MPRIS_PLAYER_PATH,
 						MPRIS_PLAYER_INTERFACE,
 						property);
+
+	if (strcasecmp(name, "Position") != 0)
+		return;
+
+	dbus_message_iter_get_basic(iter, &position);
+
+	value = position * 1000;
+
+	g_dbus_emit_signal(player->conn, MPRIS_PLAYER_PATH,
+					MPRIS_PLAYER_INTERFACE, "Seeked",
+					DBUS_TYPE_INT64, &value,
+					DBUS_TYPE_INVALID);
 }
 
 static void transport_property_changed(GDBusProxy *proxy, const char *name,
-- 
1.8.1


^ permalink raw reply related

* [PATCH BlueZ 5/6 v2] tools: Add volume support for mpris-player
From: Luiz Augusto von Dentz @ 2013-01-24  9:58 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1359021484-6958-1-git-send-email-luiz.dentz@gmail.com>

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

This uses MediaTransport1 to track the Volume changes.
---
 tools/mpris-player.c | 187 ++++++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 178 insertions(+), 9 deletions(-)

diff --git a/tools/mpris-player.c b/tools/mpris-player.c
index c8377ec..5903ca1 100644
--- a/tools/mpris-player.c
+++ b/tools/mpris-player.c
@@ -43,6 +43,7 @@
 #define BLUEZ_ADAPTER_INTERFACE "org.bluez.Adapter1"
 #define BLUEZ_MEDIA_INTERFACE "org.bluez.Media1"
 #define BLUEZ_MEDIA_PLAYER_INTERFACE "org.bluez.MediaPlayer1"
+#define BLUEZ_MEDIA_TRANSPORT_INTERFACE "org.bluez.MediaTransport1"
 #define MPRIS_BUS_NAME "org.mpris.MediaPlayer2."
 #define MPRIS_INTERFACE "org.mpris.MediaPlayer2"
 #define MPRIS_PLAYER_INTERFACE "org.mpris.MediaPlayer2.Player"
@@ -55,6 +56,7 @@ static DBusConnection *sys = NULL;
 static DBusConnection *session = NULL;
 static GDBusClient *client = NULL;
 static GSList *players = NULL;
+static GSList *transports = NULL;
 
 struct player {
 	char *name;
@@ -62,6 +64,7 @@ struct player {
 	DBusConnection *conn;
 	GDBusProxy *proxy;
 	GDBusProxy *device;
+	GDBusProxy *transport;
 };
 
 typedef int (* parse_metadata_func) (DBusMessageIter *iter, const char *key,
@@ -793,6 +796,9 @@ static void player_free(void *data)
 	g_dbus_proxy_unref(player->device);
 	g_dbus_proxy_unref(player->proxy);
 
+	if (player->transport)
+		g_dbus_proxy_unref(player->transport);
+
 	g_free(player->name);
 	g_free(player->bus_name);
 	g_free(player);
@@ -1277,6 +1283,30 @@ static gboolean get_enable(const GDBusPropertyTable *property,
 }
 
 
+static gboolean get_volume(const GDBusPropertyTable *property,
+					DBusMessageIter *iter, void *data)
+{
+	struct player *player = data;
+	double value = 0.0;
+	uint16_t volume;
+	DBusMessageIter var;
+
+	if (player->transport == NULL)
+		goto done;
+
+	if (!g_dbus_proxy_get_property(player->transport, "Volume", &var))
+		goto done;
+
+	dbus_message_iter_get_basic(&var, &volume);
+
+	value = (double) volume / 127;
+
+done:
+	dbus_message_iter_append_basic(iter, DBUS_TYPE_DOUBLE, &value);
+
+	return TRUE;
+}
+
 static const GDBusMethodTable player_methods[] = {
 	{ GDBUS_ASYNC_METHOD("PlayPause", NULL, NULL, player_toggle) },
 	{ GDBUS_ASYNC_METHOD("Play", NULL, NULL, player_play) },
@@ -1301,7 +1331,7 @@ static const GDBusPropertyTable player_properties[] = {
 	{ "Shuffle", "b", get_shuffle, set_shuffle, shuffle_exists },
 	{ "Position", "x", get_position, NULL, position_exists },
 	{ "Metadata", "a{sv}", get_track, NULL, track_exists },
-	{ "Volume", "d", get_double, NULL, NULL },
+	{ "Volume", "d", get_volume, NULL, NULL },
 	{ "CanGoNext", "b", get_enable, NULL, NULL },
 	{ "CanGoPrevious", "b", get_enable, NULL, NULL },
 	{ "CanPlay", "b", get_enable, NULL, NULL },
@@ -1355,12 +1385,33 @@ static char *mpris_busname(char *name)
 				g_strcanon(name, A_Z a_z _0_9, '_'), NULL);
 }
 
+static GDBusProxy *find_transport_by_path(const char *path)
+{
+	GSList *l;
+
+	for (l = transports; l; l = l->next) {
+		GDBusProxy *transport = l->data;
+		DBusMessageIter iter;
+		const char *value;
+
+		if (!g_dbus_proxy_get_property(transport, "Device", &iter))
+			continue;
+
+		dbus_message_iter_get_basic(&iter, &value);
+
+		if (strcmp(path, value) == 0)
+			return transport;
+	}
+
+	return NULL;
+}
+
 static void register_player(GDBusProxy *proxy)
 {
 	struct player *player;
 	DBusMessageIter iter;
 	const char *path, *name;
-	GDBusProxy *device;
+	GDBusProxy *device, *transport;
 
 	if (!g_dbus_proxy_get_property(proxy, "Device", &iter))
 		return;
@@ -1416,6 +1467,10 @@ static void register_player(GDBusProxy *proxy)
 		goto fail;
 	}
 
+	transport = find_transport_by_path(path);
+	if (transport)
+		player->transport = g_dbus_proxy_ref(transport);
+
 	return;
 
 fail:
@@ -1423,6 +1478,47 @@ fail:
 	player_free(player);
 }
 
+static struct player *find_player_by_device(const char *device)
+{
+	GSList *l;
+
+	for (l = players; l; l = l->next) {
+		struct player *player = l->data;
+		const char *path = g_dbus_proxy_get_path(player->device);
+
+		if (g_strcmp0(device, path) == 0)
+			return player;
+	}
+
+	return NULL;
+}
+
+static void register_transport(GDBusProxy *proxy)
+{
+	struct player *player;
+	DBusMessageIter iter;
+	const char *path;
+
+	if (g_slist_find(transports, proxy) != NULL)
+		return;
+
+	if (!g_dbus_proxy_get_property(proxy, "Volume", &iter))
+		return;
+
+	if (!g_dbus_proxy_get_property(proxy, "Device", &iter))
+		return;
+
+	dbus_message_iter_get_basic(&iter, &path);
+
+	transports = g_slist_append(transports, proxy);
+
+	player = find_player_by_device(path);
+	if (player == NULL || player->transport != NULL)
+		return;
+
+	player->transport = g_dbus_proxy_ref(proxy);
+}
+
 static void proxy_added(GDBusProxy *proxy, void *user_data)
 {
 	const char *interface;
@@ -1441,6 +1537,10 @@ static void proxy_added(GDBusProxy *proxy, void *user_data)
 		printf("Bluetooth Player %s found\n",
 						g_dbus_proxy_get_path(proxy));
 		register_player(proxy);
+	} else if (!strcmp(interface, BLUEZ_MEDIA_TRANSPORT_INTERFACE)) {
+		printf("Bluetooth Transport %s found\n",
+						g_dbus_proxy_get_path(proxy));
+		register_transport(proxy);
 	}
 }
 
@@ -1466,6 +1566,37 @@ static struct player *find_player(GDBusProxy *proxy)
 	return NULL;
 }
 
+static struct player *find_player_by_transport(GDBusProxy *proxy)
+{
+	GSList *l;
+
+	for (l = players; l; l = l->next) {
+		struct player *player = l->data;
+
+		if (player->transport == proxy)
+			return player;
+	}
+
+	return NULL;
+}
+
+static void unregister_transport(GDBusProxy *proxy)
+{
+	struct player *player;
+
+	if (g_slist_find(transports, proxy) == NULL)
+		return;
+
+	transports = g_slist_remove(transports, proxy);
+
+	player = find_player_by_transport(proxy);
+	if (player == NULL)
+		return;
+
+	g_dbus_proxy_unref(player->transport);
+	player->transport = NULL;
+}
+
 static void proxy_removed(GDBusProxy *proxy, void *user_data)
 {
 	const char *interface;
@@ -1491,6 +1622,10 @@ static void proxy_removed(GDBusProxy *proxy, void *user_data)
 		printf("Bluetooth Player %s removed\n",
 						g_dbus_proxy_get_path(proxy));
 		unregister_player(player);
+	} else if (strcmp(interface, BLUEZ_MEDIA_TRANSPORT_INTERFACE) == 0) {
+		printf("Bluetooth Transport %s removed\n",
+						g_dbus_proxy_get_path(proxy));
+		unregister_transport(proxy);
 	}
 }
 
@@ -1510,16 +1645,11 @@ static const char *property_to_mpris(const char *property)
 	return NULL;
 }
 
-static void property_changed(GDBusProxy *proxy, const char *name,
+static void player_property_changed(GDBusProxy *proxy, const char *name,
 					DBusMessageIter *iter, void *user_data)
 {
 	struct player *player;
-	const char *interface, *property;
-
-	interface = g_dbus_proxy_get_interface(proxy);
-
-	if (strcmp(interface, BLUEZ_MEDIA_PLAYER_INTERFACE) != 0)
-		return;
+	const char *property;
 
 	player = find_player(proxy);
 	if (player == NULL)
@@ -1534,6 +1664,45 @@ static void property_changed(GDBusProxy *proxy, const char *name,
 						property);
 }
 
+static void transport_property_changed(GDBusProxy *proxy, const char *name,
+					DBusMessageIter *iter, void *user_data)
+{
+	struct player *player;
+	DBusMessageIter var;
+	const char *path;
+
+	if (strcasecmp(name, "Volume") != 0)
+		return;
+
+	if (!g_dbus_proxy_get_property(proxy, "Device", &var))
+		return;
+
+	dbus_message_iter_get_basic(&var, &path);
+
+	player = find_player_by_device(path);
+	if (player == NULL)
+		return;
+
+	g_dbus_emit_property_changed(player->conn, MPRIS_PLAYER_PATH,
+						MPRIS_PLAYER_INTERFACE,
+						name);
+}
+
+static void property_changed(GDBusProxy *proxy, const char *name,
+					DBusMessageIter *iter, void *user_data)
+{
+	const char *interface;
+
+	interface = g_dbus_proxy_get_interface(proxy);
+
+	if (strcmp(interface, BLUEZ_MEDIA_PLAYER_INTERFACE) == 0)
+		return player_property_changed(proxy, name, iter, user_data);
+
+	if (strcmp(interface, BLUEZ_MEDIA_TRANSPORT_INTERFACE) == 0)
+		return transport_property_changed(proxy, name, iter,
+								user_data);
+}
+
 int main(int argc, char *argv[])
 {
 	guint owner_watch, properties_watch;
-- 
1.8.1


^ permalink raw reply related

* [PATCH BlueZ 4/6 v2] tools: Make mpris-player to export org.mpris.MediaPlayer2
From: Luiz Augusto von Dentz @ 2013-01-24  9:58 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1359021484-6958-1-git-send-email-luiz.dentz@gmail.com>

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

This adds support for org.mpris.MediaPlayer2 interface whic is also
mandatory accourding to MPRIS spec.
---
 tools/mpris-player.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 46 insertions(+)

diff --git a/tools/mpris-player.c b/tools/mpris-player.c
index 320309e..c8377ec 100644
--- a/tools/mpris-player.c
+++ b/tools/mpris-player.c
@@ -44,6 +44,7 @@
 #define BLUEZ_MEDIA_INTERFACE "org.bluez.Media1"
 #define BLUEZ_MEDIA_PLAYER_INTERFACE "org.bluez.MediaPlayer1"
 #define MPRIS_BUS_NAME "org.mpris.MediaPlayer2."
+#define MPRIS_INTERFACE "org.mpris.MediaPlayer2"
 #define MPRIS_PLAYER_INTERFACE "org.mpris.MediaPlayer2.Player"
 #define MPRIS_PLAYER_PATH "/org/mpris/MediaPlayer2"
 #define ERROR_INTERFACE "org.mpris.MediaPlayer2.Error"
@@ -1275,6 +1276,7 @@ static gboolean get_enable(const GDBusPropertyTable *property,
 	return TRUE;
 }
 
+
 static const GDBusMethodTable player_methods[] = {
 	{ GDBUS_ASYNC_METHOD("PlayPause", NULL, NULL, player_toggle) },
 	{ GDBUS_ASYNC_METHOD("Play", NULL, NULL, player_play) },
@@ -1309,6 +1311,39 @@ static const GDBusPropertyTable player_properties[] = {
 	{ }
 };
 
+static gboolean get_disable(const GDBusPropertyTable *property,
+					DBusMessageIter *iter, void *data)
+{
+	dbus_bool_t value = FALSE;
+
+	dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &value);
+
+	return TRUE;
+}
+
+static gboolean get_name(const GDBusPropertyTable *property,
+					DBusMessageIter *iter, void *data)
+{
+	struct player *player = data;
+
+	dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &player->name);
+
+	return TRUE;
+}
+
+static const GDBusMethodTable mpris_methods[] = {
+	{ }
+};
+
+static const GDBusPropertyTable mpris_properties[] = {
+	{ "CanQuit", "b", get_disable, NULL, NULL },
+	{ "Fullscreen", "b", get_disable, NULL, NULL },
+	{ "CanSetFullscreen", "b", get_disable, NULL, NULL },
+	{ "CanRaise", "b", get_disable, NULL, NULL },
+	{ "HasTrackList", "b", get_disable, NULL, NULL },
+	{ "Identity", "s", get_name, NULL, NULL },
+	{ }
+};
 
 #define a_z "abcdefghijklmnopqrstuvwxyz"
 #define A_Z "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
@@ -1360,6 +1395,17 @@ static void register_player(GDBusProxy *proxy)
 	}
 
 	if (!g_dbus_register_interface(player->conn, MPRIS_PLAYER_PATH,
+						MPRIS_INTERFACE,
+						mpris_methods,
+						NULL,
+						mpris_properties,
+						player, NULL)) {
+		fprintf(stderr, "Could not register interface %s",
+						MPRIS_INTERFACE);
+		goto fail;
+	}
+
+	if (!g_dbus_register_interface(player->conn, MPRIS_PLAYER_PATH,
 						MPRIS_PLAYER_INTERFACE,
 						player_methods,
 						player_signals,
-- 
1.8.1


^ permalink raw reply related

* [PATCH BlueZ 3/6 v2] tools: Convert player's properties changed signals to MPRIS
From: Luiz Augusto von Dentz @ 2013-01-24  9:58 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1359021484-6958-1-git-send-email-luiz.dentz@gmail.com>

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

Thsi convert properties changed signals from org.bluez.MediaPlayer1 to
org.mpris.MediaPlayer2.Player interface.
---
 tools/mpris-player.c | 42 +++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 41 insertions(+), 1 deletion(-)

diff --git a/tools/mpris-player.c b/tools/mpris-player.c
index 7183bf6..320309e 100644
--- a/tools/mpris-player.c
+++ b/tools/mpris-player.c
@@ -1448,6 +1448,46 @@ static void proxy_removed(GDBusProxy *proxy, void *user_data)
 	}
 }
 
+static const char *property_to_mpris(const char *property)
+{
+	if (strcasecmp(property, "Repeat") == 0)
+		return "LoopStatus";
+	else if (strcasecmp(property, "Shuffle") == 0)
+		return "Shuffle";
+	else if (strcasecmp(property, "Status") == 0)
+		return "PlaybackStatus";
+	else if (strcasecmp(property, "Position") == 0)
+		return "Position";
+	else if (strcasecmp(property, "Track") == 0)
+		return "Metadata";
+
+	return NULL;
+}
+
+static void property_changed(GDBusProxy *proxy, const char *name,
+					DBusMessageIter *iter, void *user_data)
+{
+	struct player *player;
+	const char *interface, *property;
+
+	interface = g_dbus_proxy_get_interface(proxy);
+
+	if (strcmp(interface, BLUEZ_MEDIA_PLAYER_INTERFACE) != 0)
+		return;
+
+	player = find_player(proxy);
+	if (player == NULL)
+		return;
+
+	property = property_to_mpris(name);
+	if (property == NULL)
+		return;
+
+	g_dbus_emit_property_changed(player->conn, MPRIS_PLAYER_PATH,
+						MPRIS_PLAYER_INTERFACE,
+						property);
+}
+
 int main(int argc, char *argv[])
 {
 	guint owner_watch, properties_watch;
@@ -1503,7 +1543,7 @@ int main(int argc, char *argv[])
 	g_dbus_client_set_disconnect_watch(client, disconnect_handler, NULL);
 
 	g_dbus_client_set_proxy_handlers(client, proxy_added, proxy_removed,
-								NULL, NULL);
+						property_changed, NULL);
 
 	g_main_loop_run(main_loop);
 
-- 
1.8.1


^ permalink raw reply related

* [PATCH BlueZ 2/6 v2] tools: Add support for setting Shuffle and LoopStatus to mpris-player
From: Luiz Augusto von Dentz @ 2013-01-24  9:58 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1359021484-6958-1-git-send-email-luiz.dentz@gmail.com>

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

This add write support for Shuffle and LoopStatus properties of
org.mpris.MediaPlayer2.Player interface.
---
 tools/mpris-player.c | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 78 insertions(+), 2 deletions(-)

diff --git a/tools/mpris-player.c b/tools/mpris-player.c
index d58e53f..7183bf6 100644
--- a/tools/mpris-player.c
+++ b/tools/mpris-player.c
@@ -992,6 +992,58 @@ static gboolean get_repeat(const GDBusPropertyTable *property,
 	return TRUE;
 }
 
+static const char *loopstatus_to_repeat(const char *value)
+{
+	if (strcasecmp(value, "None") == 0)
+		return "off";
+	else if (strcasecmp(value, "Track") == 0)
+		return "singletrack";
+	else if (strcasecmp(value, "Playlist") == 0)
+		return "alltracks";
+
+	return NULL;
+}
+
+static void property_result(const DBusError *err, void *user_data)
+{
+	GDBusPendingPropertySet id = GPOINTER_TO_UINT(user_data);
+
+	if (!dbus_error_is_set(err))
+		return g_dbus_pending_property_success(id);
+
+	g_dbus_pending_property_error(id, err->name, err->message);
+}
+
+static void set_repeat(const GDBusPropertyTable *property,
+			DBusMessageIter *iter, GDBusPendingPropertySet id,
+			void *data)
+{
+	struct player *player = data;
+	const char *value;
+
+	if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_STRING) {
+		g_dbus_pending_property_error(id,
+					ERROR_INTERFACE ".InvalidArguments",
+					"Invalid arguments in method call");
+		return;
+	}
+
+	dbus_message_iter_get_basic(iter, &value);
+
+	value = loopstatus_to_repeat(value);
+	if (value == NULL) {
+		g_dbus_pending_property_error(id,
+					ERROR_INTERFACE ".InvalidArguments",
+					"Invalid arguments in method call");
+		return;
+	}
+
+	g_dbus_proxy_set_property_basic(player->proxy, "Repeat",
+					DBUS_TYPE_STRING, value,
+					property_result, GUINT_TO_POINTER(id),
+					NULL);
+}
+
 static gboolean get_double(const GDBusPropertyTable *property,
 					DBusMessageIter *iter, void *data)
 {
@@ -1030,6 +1082,30 @@ static gboolean get_shuffle(const GDBusPropertyTable *property,
 	return TRUE;
 }
 
+static void set_shuffle(const GDBusPropertyTable *property,
+			DBusMessageIter *iter, GDBusPendingPropertySet id,
+			void *data)
+{
+	struct player *player = data;
+	dbus_bool_t shuffle;
+	const char *value;
+
+	if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_BOOLEAN) {
+		g_dbus_pending_property_error(id,
+					ERROR_INTERFACE ".InvalidArguments",
+					"Invalid arguments in method call");
+		return;
+	}
+
+	dbus_message_iter_get_basic(iter, &shuffle);
+	value = shuffle ? "alltracks" : "off";
+
+	g_dbus_proxy_set_property_basic(player->proxy, "Shuffle",
+					DBUS_TYPE_STRING, value,
+					property_result, GUINT_TO_POINTER(id),
+					NULL);
+}
+
 static gboolean position_exists(const GDBusPropertyTable *property, void *data)
 {
 	DBusMessageIter iter;
@@ -1216,11 +1292,11 @@ static const GDBusSignalTable player_signals[] = {
 
 static const GDBusPropertyTable player_properties[] = {
 	{ "PlaybackStatus", "s", get_status, NULL, status_exists },
-	{ "LoopStatus", "s", get_repeat, NULL, repeat_exists },
+	{ "LoopStatus", "s", get_repeat, set_repeat, repeat_exists },
 	{ "Rate", "d", get_double, NULL, NULL },
 	{ "MinimumRate", "d", get_double, NULL, NULL },
 	{ "MaximumRate", "d", get_double, NULL, NULL },
-	{ "Shuffle", "b", get_shuffle, NULL, shuffle_exists },
+	{ "Shuffle", "b", get_shuffle, set_shuffle, shuffle_exists },
 	{ "Position", "x", get_position, NULL, position_exists },
 	{ "Metadata", "a{sv}", get_track, NULL, track_exists },
 	{ "Volume", "d", get_double, NULL, NULL },
-- 
1.8.1


^ permalink raw reply related

* [PATCH BlueZ 1/6 v2] tools: Make mpris-player to export players using MPRIS interface
From: Luiz Augusto von Dentz @ 2013-01-24  9:57 UTC (permalink / raw)
  To: linux-bluetooth

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

Players found are exported in private connections using
org.mpris.MediaPlayer2.<device name> on the session bus.
---
v2: Fix generating invalid player bus name if device name contains invalid
chars.

 tools/mpris-player.c | 644 +++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 623 insertions(+), 21 deletions(-)

diff --git a/tools/mpris-player.c b/tools/mpris-player.c
index 246791a..d58e53f 100644
--- a/tools/mpris-player.c
+++ b/tools/mpris-player.c
@@ -32,6 +32,7 @@
 #include <signal.h>
 #include <getopt.h>
 #include <string.h>
+#include <inttypes.h>
 
 #include <dbus/dbus.h>
 #include <glib.h>
@@ -41,13 +42,29 @@
 #define BLUEZ_PATH "/org/bluez"
 #define BLUEZ_ADAPTER_INTERFACE "org.bluez.Adapter1"
 #define BLUEZ_MEDIA_INTERFACE "org.bluez.Media1"
+#define BLUEZ_MEDIA_PLAYER_INTERFACE "org.bluez.MediaPlayer1"
+#define MPRIS_BUS_NAME "org.mpris.MediaPlayer2."
 #define MPRIS_PLAYER_INTERFACE "org.mpris.MediaPlayer2.Player"
 #define MPRIS_PLAYER_PATH "/org/mpris/MediaPlayer2"
+#define ERROR_INTERFACE "org.mpris.MediaPlayer2.Error"
 
 static GMainLoop *main_loop;
 static GDBusProxy *adapter = NULL;
 static DBusConnection *sys = NULL;
 static DBusConnection *session = NULL;
+static GDBusClient *client = NULL;
+static GSList *players = NULL;
+
+struct player {
+	char *name;
+	char *bus_name;
+	DBusConnection *conn;
+	GDBusProxy *proxy;
+	GDBusProxy *device;
+};
+
+typedef int (* parse_metadata_func) (DBusMessageIter *iter, const char *key,
+						DBusMessageIter *metadata);
 
 static void dict_append_entry(DBusMessageIter *dict, const char *key, int type,
 								void *val);
@@ -190,7 +207,8 @@ static int parse_metadata_entry(DBusMessageIter *entry, const char *key,
 	return 0;
 }
 
-static int parse_metadata(DBusMessageIter *args, DBusMessageIter *metadata)
+static int parse_metadata(DBusMessageIter *args, DBusMessageIter *metadata,
+						parse_metadata_func func)
 {
 	DBusMessageIter dict;
 	int ctype;
@@ -216,7 +234,7 @@ static int parse_metadata(DBusMessageIter *args, DBusMessageIter *metadata)
 		dbus_message_iter_get_basic(&entry, &key);
 		dbus_message_iter_next(&entry);
 
-		if (parse_metadata_entry(&entry, key, metadata) < 0)
+		if (func(&entry, key, metadata) < 0)
 			return -EINVAL;
 
 		dbus_message_iter_next(&dict);
@@ -225,7 +243,8 @@ static int parse_metadata(DBusMessageIter *args, DBusMessageIter *metadata)
 	return 0;
 }
 
-static void append_metadata(DBusMessageIter *iter, DBusMessageIter *dict)
+static void append_metadata(DBusMessageIter *iter, DBusMessageIter *dict,
+						parse_metadata_func func)
 {
 	DBusMessageIter value, metadata;
 
@@ -237,7 +256,7 @@ static void append_metadata(DBusMessageIter *iter, DBusMessageIter *dict)
 			DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
 			DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &metadata);
 
-	parse_metadata(dict, &metadata);
+	parse_metadata(dict, &metadata, func);
 
 	dbus_message_iter_close_container(&value, &metadata);
 	dbus_message_iter_close_container(iter, &value);
@@ -260,7 +279,7 @@ static void dict_append_entry(DBusMessageIter *dict, const char *key, int type,
 	dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
 
 	if (strcasecmp(key, "Metadata") == 0)
-		append_metadata(&entry, val);
+		append_metadata(&entry, val, parse_metadata_entry);
 	else
 		append_variant(&entry, type, val);
 
@@ -509,21 +528,29 @@ done:
 static void remove_player(DBusConnection *conn, const char *sender)
 {
 	DBusMessage *msg;
-	char *path;
+	char *path, *owner;
 
 	if (!adapter)
 		return;
 
+	path = sender2path(sender);
+	dbus_connection_get_object_path_data(sys, path, (void **) &owner);
+
+	if (owner == NULL) {
+		g_free(path);
+		return;
+	}
+
 	msg = dbus_message_new_method_call(BLUEZ_BUS_NAME,
 					g_dbus_proxy_get_path(adapter),
 					BLUEZ_MEDIA_INTERFACE,
 					"UnregisterPlayer");
 	if (!msg) {
 		fprintf(stderr, "Can't allocate new method call\n");
+		g_free(path);
 		return;
 	}
 
-	path = sender2path(sender);
 	dbus_message_append_args(msg, DBUS_TYPE_OBJECT_PATH, &path,
 					DBUS_TYPE_INVALID);
 
@@ -540,10 +567,16 @@ static gboolean properties_changed(DBusConnection *conn,
 {
 	DBusMessageIter iter;
 	const char *iface;
-	char *path;
+	char *path, *owner;
 
 	dbus_message_iter_init(msg, &iter);
 
+	path = sender2path(dbus_message_get_sender(msg));
+	dbus_connection_get_object_path_data(sys, path, (void **) &owner);
+
+	if (owner == NULL)
+		goto done;
+
 	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
 		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 
@@ -553,14 +586,28 @@ static gboolean properties_changed(DBusConnection *conn,
 
 	dbus_message_iter_next(&iter);
 
-	path = sender2path(dbus_message_get_sender(msg));
 	parse_properties(conn, path, &iter, NULL);
 
+done:
 	g_free(path);
 
 	return TRUE;
 }
 
+static struct player *find_player_by_bus_name(const char *name)
+{
+	GSList *l;
+
+	for (l = players; l; l = l->next) {
+		struct player *player = l->data;
+
+		if (strcmp(player->bus_name, name) == 0)
+			return player;
+	}
+
+	return NULL;
+}
+
 static gboolean name_owner_changed(DBusConnection *conn,
 						DBusMessage *msg, void *data)
 {
@@ -581,7 +628,7 @@ static gboolean name_owner_changed(DBusConnection *conn,
 	if (*new == '\0') {
 		printf("player %s at %s disappear\n", name, old);
 		remove_player(conn, old);
-	} else {
+	} else if (find_player_by_bus_name(name) == NULL) {
 		printf("player %s at %s found\n", name, new);
 		add_player(conn, name, new);
 	}
@@ -733,23 +780,570 @@ static void disconnect_handler(DBusConnection *connection, void *user_data)
 	printf("org.bluez disappeared\n");
 }
 
-static void proxy_added(GDBusProxy *proxy, void *user_data)
+static void player_free(void *data)
 {
-	const char *interface;
+	struct player *player = data;
+
+	if (player->conn) {
+		dbus_connection_close(player->conn);
+		dbus_connection_unref(player->conn);
+	}
+
+	g_dbus_proxy_unref(player->device);
+	g_dbus_proxy_unref(player->proxy);
+
+	g_free(player->name);
+	g_free(player->bus_name);
+	g_free(player);
+}
+
+struct pending_call {
+	struct player *player;
+	DBusMessage *msg;
+};
+
+static void pending_call_free(void *data)
+{
+	struct pending_call *p = data;
+
+	if (p->msg)
+		dbus_message_unref(p->msg);
+
+	g_free(p);
+}
+
+static void player_reply(DBusMessage *message, void *user_data)
+{
+	struct pending_call *p = user_data;
+	struct player *player = p->player;
+	DBusMessage *msg = p->msg;
+	DBusMessage *reply;
+	DBusError err;
+
+	dbus_error_init(&err);
+	if (dbus_set_error_from_message(&err, message)) {
+		fprintf(stderr, "error: %s", err.name);
+		reply = g_dbus_create_error(msg, err.name, err.message);
+		dbus_error_free(&err);
+	} else
+		reply = g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+
+	g_dbus_send_message(player->conn, reply);
+}
+
+static void player_control(struct player *player, DBusMessage *msg,
+							const char *name)
+{
+	struct pending_call *p;
+
+	p = g_new0(struct pending_call, 1);
+	p->player = player;
+	p->msg = dbus_message_ref(msg);
+
+	g_dbus_proxy_method_call(player->proxy, name, NULL, player_reply,
+						p, pending_call_free);
+}
+
+static DBusMessage *player_toggle(DBusConnection *conn, DBusMessage *msg,
+								void *data)
+{
+	struct player *player = data;
+	DBusMessageIter value;
+	const char *status;
+
+	if (!g_dbus_proxy_get_property(player->proxy, "Status", &value))
+		return FALSE;
+
+	dbus_message_iter_get_basic(&value, &status);
+
+	if (strcasecmp(status, "Playing") == 0)
+		player_control(player, msg, "Pause");
+	else
+		player_control(player, msg, "Play");
+
+	return NULL;
+}
+
+static DBusMessage *player_play(DBusConnection *conn, DBusMessage *msg,
+								void *data)
+{
+	struct player *player = data;
+
+	player_control(player, msg, "Play");
+
+	return NULL;
+}
+
+static DBusMessage *player_pause(DBusConnection *conn, DBusMessage *msg,
+								void *data)
+{
+	struct player *player = data;
+
+	player_control(player, msg, "Pause");
+
+	return NULL;
+}
+
+static DBusMessage *player_stop(DBusConnection *conn, DBusMessage *msg,
+								void *data)
+{
+	struct player *player = data;
+
+	player_control(player, msg, "Stop");
+
+	return NULL;
+}
+
+static DBusMessage *player_next(DBusConnection *conn, DBusMessage *msg,
+								void *data)
+{
+	struct player *player = data;
+
+	player_control(player, msg, "Next");
+
+	return NULL;
+}
+
+static DBusMessage *player_previous(DBusConnection *conn, DBusMessage *msg,
+								void *data)
+{
+	struct player *player = data;
+
+	player_control(player, msg, "Previous");
+
+	return NULL;
+}
+
+static gboolean status_exists(const GDBusPropertyTable *property, void *data)
+{
+	DBusMessageIter iter;
+	struct player *player = data;
+
+	return g_dbus_proxy_get_property(player->proxy, "Status", &iter);
+}
+
+static const char *status_to_playback(const char *status)
+{
+	if (strcasecmp(status, "playing") == 0)
+		return "Playing";
+	else if (strcasecmp(status, "paused") == 0)
+		return "Paused";
+	else
+		return "Stopped";
+}
+
+static gboolean get_status(const GDBusPropertyTable *property,
+					DBusMessageIter *iter, void *data)
+{
+	struct player *player = data;
+	DBusMessageIter value;
+	const char *status;
+
+	if (!g_dbus_proxy_get_property(player->proxy, "Status", &value))
+		return FALSE;
+
+	dbus_message_iter_get_basic(&value, &status);
+
+	status = status_to_playback(status);
+
+	dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &status);
+
+	return TRUE;
+}
+
+static gboolean repeat_exists(const GDBusPropertyTable *property, void *data)
+{
+	DBusMessageIter iter;
+	struct player *player = data;
+
+	return g_dbus_proxy_get_property(player->proxy, "Repeat", &iter);
+}
+
+static const char *repeat_to_loopstatus(const char *value)
+{
+	if (strcasecmp(value, "off") == 0)
+		return "None";
+	else if (strcasecmp(value, "singletrack") == 0)
+		return "Track";
+	else if (strcasecmp(value, "alltracks") == 0)
+		return "Playlist";
+
+	return NULL;
+}
+
+static gboolean get_repeat(const GDBusPropertyTable *property,
+					DBusMessageIter *iter, void *data)
+{
+	struct player *player = data;
+	DBusMessageIter value;
+	const char *status;
+
+	if (!g_dbus_proxy_get_property(player->proxy, "Repeat", &value))
+		return FALSE;
+
+	dbus_message_iter_get_basic(&value, &status);
+
+	status = repeat_to_loopstatus(status);
+	if (status == NULL)
+		return FALSE;
+
+	dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &status);
+
+	return TRUE;
+}
+
+static gboolean get_double(const GDBusPropertyTable *property,
+					DBusMessageIter *iter, void *data)
+{
+	double value = 1.0;
+
+	dbus_message_iter_append_basic(iter, DBUS_TYPE_DOUBLE, &value);
+
+	return TRUE;
+}
+
+static gboolean shuffle_exists(const GDBusPropertyTable *property, void *data)
+{
+	DBusMessageIter iter;
+	struct player *player = data;
+
+	return g_dbus_proxy_get_property(player->proxy, "Shuffle", &iter);
+}
+
+static gboolean get_shuffle(const GDBusPropertyTable *property,
+					DBusMessageIter *iter, void *data)
+{
+	struct player *player = data;
+	DBusMessageIter value;
+	const char *string;
+	dbus_bool_t shuffle;
+
+	if (!g_dbus_proxy_get_property(player->proxy, "Shuffle", &value))
+		return FALSE;
+
+	dbus_message_iter_get_basic(&value, &string);
+
+	shuffle = strcmp(string, "off") != 0;
+
+	dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &shuffle);
+
+	return TRUE;
+}
+
+static gboolean position_exists(const GDBusPropertyTable *property, void *data)
+{
+	DBusMessageIter iter;
+	struct player *player = data;
+
+	return g_dbus_proxy_get_property(player->proxy, "Position", &iter);
+}
 
-	if (adapter != NULL)
+static gboolean get_position(const GDBusPropertyTable *property,
+					DBusMessageIter *iter, void *data)
+{
+	struct player *player = data;
+	DBusMessageIter var;
+	uint32_t position;
+	int64_t value;
+
+	if (!g_dbus_proxy_get_property(player->proxy, "Position", &var))
+		return FALSE;
+
+	dbus_message_iter_get_basic(&var, &position);
+
+	value = position * 1000;
+
+	dbus_message_iter_append_basic(iter, DBUS_TYPE_INT64, &value);
+
+	return TRUE;
+}
+
+static gboolean track_exists(const GDBusPropertyTable *property, void *data)
+{
+	DBusMessageIter iter;
+	struct player *player = data;
+
+	return g_dbus_proxy_get_property(player->proxy, "Track", &iter);
+}
+
+static gboolean parse_string_metadata(DBusMessageIter *iter, const char *key,
+						DBusMessageIter *metadata)
+{
+	const char *value;
+
+	if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_STRING)
+		return FALSE;
+
+	dbus_message_iter_get_basic(iter, &value);
+
+	dict_append_entry(metadata, key, DBUS_TYPE_STRING, &value);
+
+	return TRUE;
+}
+
+static gboolean parse_array_metadata(DBusMessageIter *iter, const char *key,
+						DBusMessageIter *metadata)
+{
+	char **value;
+
+	if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_STRING)
+		return FALSE;
+
+	value = dbus_malloc0(sizeof(char *));
+
+	dbus_message_iter_get_basic(iter, &(value[0]));
+
+	dict_append_array(metadata, key, DBUS_TYPE_STRING, &value, 1);
+
+	dbus_free(value);
+
+	return TRUE;
+}
+
+static gboolean parse_int64_metadata(DBusMessageIter *iter, const char *key,
+						DBusMessageIter *metadata)
+{
+	uint32_t duration;
+	int64_t value;
+
+	if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_UINT32)
+		return FALSE;
+
+	dbus_message_iter_get_basic(iter, &duration);
+
+	value = duration * 1000;
+
+	dict_append_entry(metadata, key, DBUS_TYPE_INT64, &value);
+
+	return TRUE;
+}
+
+static gboolean parse_int32_metadata(DBusMessageIter *iter, const char *key,
+						DBusMessageIter *metadata)
+{
+	uint32_t value;
+
+	if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_UINT32)
+		return FALSE;
+
+	dbus_message_iter_get_basic(iter, &value);
+
+	dict_append_entry(metadata, key, DBUS_TYPE_INT32, &value);
+
+	return TRUE;
+}
+
+static int parse_track_entry(DBusMessageIter *entry, const char *key,
+						DBusMessageIter *metadata)
+{
+	DBusMessageIter var;
+
+	printf("metadata %s found\n", key);
+
+	if (dbus_message_iter_get_arg_type(entry) != DBUS_TYPE_VARIANT)
+		return -EINVAL;
+
+	dbus_message_iter_recurse(entry, &var);
+
+	if (strcasecmp(key, "Title") == 0) {
+		if (!parse_string_metadata(&var, "xesam:title", metadata))
+			return -EINVAL;
+	} else if (strcasecmp(key, "Artist") == 0) {
+		if (!parse_array_metadata(&var, "xesam:artist", metadata))
+			return -EINVAL;
+	} else if (strcasecmp(key, "Album") == 0) {
+		if (!parse_string_metadata(&var, "xesam:album", metadata))
+			return -EINVAL;
+	} else if (strcasecmp(key, "Genre") == 0) {
+		if (!parse_array_metadata(&var, "xesam:genre", metadata))
+			return -EINVAL;
+	} else if (strcasecmp(key, "Duration") == 0) {
+		if (!parse_int64_metadata(&var, "mpris:length", metadata))
+			return -EINVAL;
+	} else if (strcasecmp(key, "TrackNumber") == 0) {
+		if (!parse_int32_metadata(&var, "xesam:trackNumber", metadata))
+			return -EINVAL;
+	}
+
+	return 0;
+}
+
+static gboolean get_track(const GDBusPropertyTable *property,
+					DBusMessageIter *iter, void *data)
+{
+	struct player *player = data;
+	DBusMessageIter var, metadata;
+
+	if (!g_dbus_proxy_get_property(player->proxy, "Track", &var))
+		return FALSE;
+
+	dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
+			DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+			DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
+			DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &metadata);
+
+	parse_metadata(&var, &metadata, parse_track_entry);
+
+	dbus_message_iter_close_container(iter, &metadata);
+
+	return TRUE;
+}
+
+static gboolean get_enable(const GDBusPropertyTable *property,
+					DBusMessageIter *iter, void *data)
+{
+	dbus_bool_t value = TRUE;
+
+	dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &value);
+
+	return TRUE;
+}
+
+static const GDBusMethodTable player_methods[] = {
+	{ GDBUS_ASYNC_METHOD("PlayPause", NULL, NULL, player_toggle) },
+	{ GDBUS_ASYNC_METHOD("Play", NULL, NULL, player_play) },
+	{ GDBUS_ASYNC_METHOD("Pause", NULL, NULL, player_pause) },
+	{ GDBUS_ASYNC_METHOD("Stop", NULL, NULL, player_stop) },
+	{ GDBUS_ASYNC_METHOD("Next", NULL, NULL, player_next) },
+	{ GDBUS_ASYNC_METHOD("Previous", NULL, NULL, player_previous) },
+	{ }
+};
+
+static const GDBusSignalTable player_signals[] = {
+	{ GDBUS_SIGNAL("Seeked", GDBUS_ARGS({"Position", "x"})) },
+	{ }
+};
+
+static const GDBusPropertyTable player_properties[] = {
+	{ "PlaybackStatus", "s", get_status, NULL, status_exists },
+	{ "LoopStatus", "s", get_repeat, NULL, repeat_exists },
+	{ "Rate", "d", get_double, NULL, NULL },
+	{ "MinimumRate", "d", get_double, NULL, NULL },
+	{ "MaximumRate", "d", get_double, NULL, NULL },
+	{ "Shuffle", "b", get_shuffle, NULL, shuffle_exists },
+	{ "Position", "x", get_position, NULL, position_exists },
+	{ "Metadata", "a{sv}", get_track, NULL, track_exists },
+	{ "Volume", "d", get_double, NULL, NULL },
+	{ "CanGoNext", "b", get_enable, NULL, NULL },
+	{ "CanGoPrevious", "b", get_enable, NULL, NULL },
+	{ "CanPlay", "b", get_enable, NULL, NULL },
+	{ "CanPause", "b", get_enable, NULL, NULL },
+	{ "CanSeek", "b", get_enable, NULL, NULL },
+	{ "CanControl", "b", get_enable, NULL, NULL },
+	{ }
+};
+
+
+#define a_z "abcdefghijklmnopqrstuvwxyz"
+#define A_Z "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+#define _0_9 "_0123456789"
+
+static char *mpris_busname(char *name)
+{
+	return g_strconcat(MPRIS_BUS_NAME,
+				g_strcanon(name, A_Z a_z _0_9, '_'), NULL);
+}
+
+static void register_player(GDBusProxy *proxy)
+{
+	struct player *player;
+	DBusMessageIter iter;
+	const char *path, *name;
+	GDBusProxy *device;
+
+	if (!g_dbus_proxy_get_property(proxy, "Device", &iter))
+		return;
+
+	dbus_message_iter_get_basic(&iter, &path);
+
+	device = g_dbus_proxy_new(client, path, "org.bluez.Device1");
+	if (device == NULL)
+		return;
+
+	if (!g_dbus_proxy_get_property(device, "Name", &iter))
 		return;
 
+	dbus_message_iter_get_basic(&iter, &name);
+
+	player = g_new0(struct player, 1);
+	player->name = g_strdup(name);
+	player->bus_name = mpris_busname(player->name);
+	player->proxy = g_dbus_proxy_ref(proxy);
+	player->device = device;
+
+	players = g_slist_prepend(players, player);
+
+	printf("Player %s created\n", player->bus_name);
+
+	player->conn = g_dbus_setup_private(DBUS_BUS_SESSION, player->bus_name,
+									NULL);
+	if (!session) {
+		fprintf(stderr, "Could not register bus name %s",
+							player->bus_name);
+		goto fail;
+	}
+
+	if (!g_dbus_register_interface(player->conn, MPRIS_PLAYER_PATH,
+						MPRIS_PLAYER_INTERFACE,
+						player_methods,
+						player_signals,
+						player_properties,
+						player, player_free)) {
+		fprintf(stderr, "Could not register interface %s",
+						MPRIS_PLAYER_INTERFACE);
+		goto fail;
+	}
+
+	return;
+
+fail:
+	players = g_slist_remove(players, player);
+	player_free(player);
+}
+
+static void proxy_added(GDBusProxy *proxy, void *user_data)
+{
+	const char *interface;
+
 	interface = g_dbus_proxy_get_interface(proxy);
 
 	if (!strcmp(interface, BLUEZ_ADAPTER_INTERFACE)) {
+		if (adapter != NULL)
+			return;
+
 		printf("Bluetooth Adapter %s found\n",
 						g_dbus_proxy_get_path(proxy));
 		adapter = proxy;
 		list_names(session);
+	} else if (!strcmp(interface, BLUEZ_MEDIA_PLAYER_INTERFACE)) {
+		printf("Bluetooth Player %s found\n",
+						g_dbus_proxy_get_path(proxy));
+		register_player(proxy);
 	}
 }
 
+static void unregister_player(struct player *player)
+{
+	players = g_slist_remove(players, player);
+
+	g_dbus_unregister_interface(player->conn, MPRIS_PLAYER_PATH,
+						MPRIS_PLAYER_INTERFACE);
+}
+
+static struct player *find_player(GDBusProxy *proxy)
+{
+	GSList *l;
+
+	for (l = players; l; l = l->next) {
+		struct player *player = l->data;
+
+		if (player->proxy == proxy)
+			return player;
+	}
+
+	return NULL;
+}
+
 static void proxy_removed(GDBusProxy *proxy, void *user_data)
 {
 	const char *interface;
@@ -759,19 +1353,27 @@ static void proxy_removed(GDBusProxy *proxy, void *user_data)
 
 	interface = g_dbus_proxy_get_interface(proxy);
 
-	if (strcmp(interface, BLUEZ_ADAPTER_INTERFACE))
-		return;
+	if (strcmp(interface, BLUEZ_ADAPTER_INTERFACE) == 0) {
+		if (adapter != proxy)
+			return;
+		printf("Bluetooth Adapter %s removed\n",
+						g_dbus_proxy_get_path(proxy));
+		adapter = NULL;
+	} else if (strcmp(interface, BLUEZ_MEDIA_PLAYER_INTERFACE) == 0) {
+		struct player *player;
 
-	if (adapter != proxy)
-		return;
+		player = find_player(proxy);
+		if (player == NULL)
+			return;
 
-	printf("Bluetooth Adapter %s removed\n", g_dbus_proxy_get_path(proxy));
-	adapter = NULL;
+		printf("Bluetooth Player %s removed\n",
+						g_dbus_proxy_get_path(proxy));
+		unregister_player(player);
+	}
 }
 
 int main(int argc, char *argv[])
 {
-	GDBusClient *client;
 	guint owner_watch, properties_watch;
 	struct sigaction sa;
 	int opt;
@@ -825,7 +1427,7 @@ int main(int argc, char *argv[])
 	g_dbus_client_set_disconnect_watch(client, disconnect_handler, NULL);
 
 	g_dbus_client_set_proxy_handlers(client, proxy_added, proxy_removed,
-							NULL, NULL);
+								NULL, NULL);
 
 	g_main_loop_run(main_loop);
 
-- 
1.8.1


^ permalink raw reply related

* [RFC PATCH v0 6/6] Bluetooth: Add support for UUID-128 bit parsing for EIR
From: Syam Sidhardhan @ 2013-01-24  5:57 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1359007079-11724-1-git-send-email-s.syam@samsung.com>

This patch add the support for UUID-128 bit parsing for the EIR.

Signed-off-by: Syam Sidhardhan <s.syam@samsung.com>
Tested-by: Chan-yeol Park <chanyeol.park@samsung.com>
---
 net/bluetooth/mgmt.c |   75 +++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 74 insertions(+), 1 deletion(-)

diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index e1fbf95..52cce2f 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -586,6 +586,52 @@ static u16 update_eir_uuid32_list(u8 *list32, u8 *uuid, bool updated_16, bool up
 	return eir_len;
 }
 
+static u16 update_eir_uuid128_list(u8 *list128, u8 *uuid, bool updated_16, bool updated_32, u16 eir_len, bool *truncated)
+{
+	int i;
+	u128 *uuid128_list = (u128 *) list128;
+	u128 u;
+
+	memset(u.data, 0, sizeof(u128));
+
+	/* Stop if not enough space to put next UUID128 */
+	if (eir_len + 2 + sizeof(u128) > HCI_MAX_EIR_LENGTH) {
+		*truncated = true;
+		return 1;
+	}
+
+	i = 0;
+
+	/* Comparing uuid128_list[i] with 0*/
+	while (memcmp(uuid128_list[i].data, u.data, sizeof(u128))) {
+		if (!memcmp(uuid128_list[i].data, uuid, sizeof(u128)))
+			break;
+
+		++i;
+	}
+
+	if (!memcmp(uuid128_list[i].data, u.data, sizeof(u128))) {
+
+		/* if any other uuid types has been already added into the
+		 * corresponding list, then consider it's header length(2 bytes)
+		 * in eir_len calculation.
+		 */
+		if (!memcmp(uuid128_list[0].data, u.data, sizeof(u128))) {
+			if (updated_16)
+				eir_len += 2;
+
+			if (updated_32)
+				eir_len += 2;
+
+		}
+
+		memcpy(uuid128_list[i].data, uuid, sizeof(u128));
+		eir_len += sizeof(u128);
+	}
+
+	return eir_len;
+}
+
 static u8 *prepare_eir_from_list(u8 *list, u8 *ptr, u16 type, bool truncated)
 {
 	int i;
@@ -666,10 +712,12 @@ static void create_eir(struct hci_dev *hdev, u8 *data)
 	u16 eir_len = 0;
 	u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)];
 	u32 uuid32_list[HCI_MAX_EIR_LENGTH / sizeof(u32)];
+	u128 uuid128_list[HCI_MAX_EIR_LENGTH / sizeof(u128)];
 	struct bt_uuid *uuid;
 	size_t name_len;
-	bool truncated_16 = false, truncated_32 = false;
+	bool truncated_16 = false, truncated_32 = false, truncated_128 = false;
 	bool updated_128 = false;
+	u128 u;
 
 	name_len = strlen(hdev->dev_name);
 
@@ -714,6 +762,8 @@ static void create_eir(struct hci_dev *hdev, u8 *data)
 
 	memset(uuid16_list, 0, sizeof(uuid16_list));
 	memset(uuid32_list, 0, sizeof(uuid32_list));
+	memset(uuid128_list, 0, sizeof(uuid128_list));
+	memset(u.data, 0, sizeof(u128));
 
 	list_for_each_entry(uuid, &hdev->uuids, list) {
 		u16 uuid_type;
@@ -746,6 +796,23 @@ static void create_eir(struct hci_dev *hdev, u8 *data)
 				break;
 
 			eir_len = ret;
+		} else {
+			ret = update_eir_uuid128_list((u8 *) uuid128_list,
+						      uuid->uuid,
+						      uuid16_list[0] ? 1 : 0,
+						      uuid32_list[0] ? 1 : 0,
+						      eir_len,
+						      &truncated_128);
+			/* Truncated */
+			if (ret == 1)
+				break;
+
+			/* In other cases we will directly check uuid*_list[0].
+			 * Here we use a flag updated_128 to avoid memcmp().
+			 */
+			updated_128 = true;
+
+			eir_len = ret;
 		}
 	} /* list_for_each_entry end */
 
@@ -760,6 +827,12 @@ static void create_eir(struct hci_dev *hdev, u8 *data)
 					    EIR_TYPE_UUID32, truncated_32);
 		eir_len += 2;
 	}
+
+	if (memcmp(uuid128_list[0].data, u.data, sizeof(u128)) != 0) {
+		ptr = prepare_eir_from_list((u8 *) uuid128_list, ptr,
+					    EIR_TYPE_UUID128, truncated_128);
+		eir_len += 2;
+	}
 }
 
 static int update_eir(struct hci_dev *hdev)
-- 
1.7.9.5


^ permalink raw reply related

* [RFC PATCH v0 5/6] Bluetooth: Add support for UUID-32 bit parsing for EIR
From: Syam Sidhardhan @ 2013-01-24  5:57 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1359007079-11724-1-git-send-email-s.syam@samsung.com>

This patch add the support for UUID 32-bit parsing for EIR.

Signed-off-by: Syam Sidhardhan <s.syam@samsung.com>
Tested-by: Chan-yeol Park <chanyeol.park@samsung.com>
---
 net/bluetooth/mgmt.c |   72 +++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 71 insertions(+), 1 deletion(-)

diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 446e4d3..e1fbf95 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -483,6 +483,18 @@ static u16 get_uuid16(u8 *uuid128)
 	return (u16) val;
 }
 
+static u32 get_uuid32(u8 *uuid128)
+{
+	int i;
+
+	for (i = 0; i < 12; i++) {
+		if (bluetooth_base_uuid[i] != uuid128[i])
+			return 0;
+	}
+
+	return get_unaligned_le32(&uuid128[12]);
+}
+
 static u16 update_eir_uuid16_list(u8 *list16, u8 *uuid, bool updated_32, bool updated_128, u16 eir_len, bool *truncated)
 {
 	int i;
@@ -533,6 +545,47 @@ static u16 update_eir_uuid16_list(u8 *list16, u8 *uuid, bool updated_32, bool up
 	return eir_len;
 }
 
+static u16 update_eir_uuid32_list(u8 *list32, u8 *uuid, bool updated_16, bool updated_128, u16 eir_len, bool *truncated)
+{
+	int i;
+	u32 uuid32;
+	u32 *uuid32_list = (u32 *) list32;
+
+	/* Group all UUID32 types */
+	uuid32 = get_uuid32(uuid);
+
+	/* Stop if not enough space to put next UUID32 */
+	if (eir_len + 2 + sizeof(u32) > HCI_MAX_EIR_LENGTH) {
+		*truncated = true;
+		return 1;
+	}
+
+	/* Check for duplicates */
+	for (i = 0; uuid32_list[i] != 0; i++)
+		if (uuid32_list[i] == uuid32)
+			break;
+
+	if (uuid32_list[i] == 0) {
+
+		/* if any other uuid types has been already added into the
+		 * corresponding list, then consider it's header length(2 bytes)
+		 * in eir_len calculation.
+		 */
+		if (uuid32_list[0] == 0) {
+			if (updated_16)
+				eir_len += 2;
+
+			if (updated_128 == true)
+				eir_len += 2;
+		}
+
+		uuid32_list[i] = uuid32;
+		eir_len += sizeof(u32);
+	}
+
+	return eir_len;
+}
+
 static u8 *prepare_eir_from_list(u8 *list, u8 *ptr, u16 type, bool truncated)
 {
 	int i;
@@ -615,7 +668,7 @@ static void create_eir(struct hci_dev *hdev, u8 *data)
 	u32 uuid32_list[HCI_MAX_EIR_LENGTH / sizeof(u32)];
 	struct bt_uuid *uuid;
 	size_t name_len;
-	bool truncated_16 = false;
+	bool truncated_16 = false, truncated_32 = false;
 	bool updated_128 = false;
 
 	name_len = strlen(hdev->dev_name);
@@ -682,6 +735,17 @@ static void create_eir(struct hci_dev *hdev, u8 *data)
 				break;
 
 			eir_len = ret;
+		} else if (uuid_type == EIR_TYPE_UUID32) {
+			ret = update_eir_uuid32_list((u8 *) uuid32_list,
+						     uuid->uuid,
+						     uuid16_list[0] ? 1 : 0,
+						     updated_128, eir_len,
+						     &truncated_32);
+			/* Truncated */
+			if (ret == 1)
+				break;
+
+			eir_len = ret;
 		}
 	} /* list_for_each_entry end */
 
@@ -690,6 +754,12 @@ static void create_eir(struct hci_dev *hdev, u8 *data)
 					    EIR_TYPE_UUID16, truncated_16);
 		eir_len += 2;
 	}
+
+	if (uuid32_list[0]) {
+		ptr = prepare_eir_from_list((u8 *) uuid32_list, ptr,
+					    EIR_TYPE_UUID32, truncated_32);
+		eir_len += 2;
+	}
 }
 
 static int update_eir(struct hci_dev *hdev)
-- 
1.7.9.5


^ permalink raw reply related

* [RFC PATCH v0 4/6] Bluetooth: Add EIR UUID-16 bit parsing for EIR
From: Syam Sidhardhan @ 2013-01-24  5:57 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1359007079-11724-1-git-send-email-s.syam@samsung.com>

Here we are enhancing the existing code to support 16bit UUID's along
with other types. Also it fixes one issue related to EIR 16 bit UUID
updation. Earlier UUID 16bit updation fails further when any other
non 16 bit UUID types are trying to get registed.

Signed-off-by: Syam Sidhardhan <s.syam@samsung.com>
Tested-by: Chan-yeol Park <chanyeol.park@samsung.com>
---
 net/bluetooth/mgmt.c |  117 ++++++++++++++++++++++++++++++++------------------
 1 file changed, 75 insertions(+), 42 deletions(-)

diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index d2569f8..446e4d3 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -483,6 +483,56 @@ static u16 get_uuid16(u8 *uuid128)
 	return (u16) val;
 }
 
+static u16 update_eir_uuid16_list(u8 *list16, u8 *uuid, bool updated_32, bool updated_128, u16 eir_len, bool *truncated)
+{
+	int i;
+	u16 uuid16;
+	u16 *uuid16_list = (u16 *) list16;
+
+	/* Group all UUID16 types */
+	uuid16 = get_uuid16(uuid);
+	if (uuid16 == 0)
+		return 0;
+
+	if (uuid16 < 0x1100)
+		return 0;
+
+	if (uuid16 == PNP_INFO_SVCLASS_ID)
+		return 0;
+
+	/* Stop if not enough space to put next UUID16 */
+	if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) {
+		*truncated = true;
+		return 1;
+	}
+
+	/* Check for duplicates */
+	for (i = 0; uuid16_list[i] != 0; i++)
+		if (uuid16_list[i] == uuid16)
+			return 0;
+
+	if (uuid16_list[i] == 0) {
+
+		/* if any other uuid types has been already added into the
+		 * corresponding list, then consider it's header length(2 bytes)
+		 * in eir_len calculation.
+		 */
+		if (uuid16_list[0] == 0) {
+
+			if (updated_32)
+				eir_len += 2;
+
+			if (updated_128 == true)
+				eir_len += 2;
+		}
+
+		uuid16_list[i] = uuid16;
+		eir_len += sizeof(u16);
+	}
+
+	return eir_len;
+}
+
 static u8 *prepare_eir_from_list(u8 *list, u8 *ptr, u16 type, bool truncated)
 {
 	int i;
@@ -562,9 +612,11 @@ static void create_eir(struct hci_dev *hdev, u8 *data)
 	u8 *ptr = data;
 	u16 eir_len = 0;
 	u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)];
-	int i, truncated = 0;
+	u32 uuid32_list[HCI_MAX_EIR_LENGTH / sizeof(u32)];
 	struct bt_uuid *uuid;
 	size_t name_len;
+	bool truncated_16 = false;
+	bool updated_128 = false;
 
 	name_len = strlen(hdev->dev_name);
 
@@ -608,54 +660,35 @@ static void create_eir(struct hci_dev *hdev, u8 *data)
 	}
 
 	memset(uuid16_list, 0, sizeof(uuid16_list));
+	memset(uuid32_list, 0, sizeof(uuid32_list));
 
-	/* Group all UUID16 types */
 	list_for_each_entry(uuid, &hdev->uuids, list) {
-		u16 uuid16;
-
-		uuid16 = get_uuid16(uuid->uuid);
-		if (uuid16 == 0)
-			return;
-
-		if (uuid16 < 0x1100)
-			continue;
-
-		if (uuid16 == PNP_INFO_SVCLASS_ID)
-			continue;
-
-		/* Stop if not enough space to put next UUID */
-		if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) {
-			truncated = 1;
-			break;
-		}
-
-		/* Check for duplicates */
-		for (i = 0; uuid16_list[i] != 0; i++)
-			if (uuid16_list[i] == uuid16)
+		u16 uuid_type;
+		u16 ret;
+
+		uuid_type = get_uuid_type(uuid->uuid);
+
+		if (uuid_type == EIR_TYPE_UUID16) {
+			ret = update_eir_uuid16_list((u8 *) uuid16_list,
+						     uuid->uuid,
+						     uuid32_list[0] ? 1 : 0,
+						     updated_128, eir_len,
+						     &truncated_16);
+			if (ret == 0)
+				continue;
+
+			/* Truncated */
+			if (ret == 1)
 				break;
 
-		if (uuid16_list[i] == 0) {
-			uuid16_list[i] = uuid16;
-			eir_len += sizeof(u16);
+			eir_len = ret;
 		}
-	}
+	} /* list_for_each_entry end */
 
-	if (uuid16_list[0] != 0) {
-		u8 *length = ptr;
-
-		/* EIR Data type */
-		ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL;
-
-		ptr += 2;
+	if (uuid16_list[0]) {
+		ptr = prepare_eir_from_list((u8 *) uuid16_list, ptr,
+					    EIR_TYPE_UUID16, truncated_16);
 		eir_len += 2;
-
-		for (i = 0; uuid16_list[i] != 0; i++) {
-			*ptr++ = (uuid16_list[i] & 0x00ff);
-			*ptr++ = (uuid16_list[i] & 0xff00) >> 8;
-		}
-
-		/* EIR Data length */
-		*length = (i * sizeof(u16)) + 1;
 	}
 }
 
-- 
1.7.9.5


^ permalink raw reply related

* [RFC PATCH v0 3/6] Bluetooth: Add helper function to prepare the EIR packet from list
From: Syam Sidhardhan @ 2013-01-24  5:57 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1359007079-11724-1-git-send-email-s.syam@samsung.com>

This function is used to prepare the final eir data from the
various list. It returns the updated pointer to the buffer.

Signed-off-by: Syam Sidhardhan <s.syam@samsung.com>
Tested-by: Chan-yeol Park <chanyeol.park@samsung.com>
---
 net/bluetooth/mgmt.c |   79 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 79 insertions(+)

diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 0f32986..d2569f8 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -41,6 +41,11 @@ bool enable_hs;
 #define EIR_TYPE_UUID32 2
 #define EIR_TYPE_UUID128 3
 
+/* UUID128 type */
+typedef struct {
+	u8 data[16];
+} u128;
+
 static const u16 mgmt_commands[] = {
 	MGMT_OP_READ_INDEX_LIST,
 	MGMT_OP_READ_INFO,
@@ -478,6 +483,80 @@ static u16 get_uuid16(u8 *uuid128)
 	return (u16) val;
 }
 
+static u8 *prepare_eir_from_list(u8 *list, u8 *ptr, u16 type, bool truncated)
+{
+	int i;
+	if (type == EIR_TYPE_UUID16) {
+		u8 *length = ptr;
+		u16 *uuid16_list = (u16 *) list;
+
+		/* EIR Data type */
+		ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL;
+
+		ptr += 2;
+		for (i = 0; uuid16_list[i] != 0; i++) {
+			*ptr++ = (uuid16_list[i] & 0x00ff);
+			*ptr++ = (uuid16_list[i] & 0xff00) >> 8;
+		}
+
+		/* EIR Data length */
+		*length = (i * sizeof(u16)) + 1;
+		return ptr;
+	}
+
+	if (type == EIR_TYPE_UUID32) {
+		u8 *length = ptr;
+		u32 *uuid32_list = (u32 *) list;
+
+		/* EIR Data type */
+		ptr[1] = truncated ? EIR_UUID32_SOME : EIR_UUID32_ALL;
+
+		ptr += 2;
+
+		for (i = 0; uuid32_list[i] != 0; i++) {
+			*ptr++ = (uuid32_list[i] & 0x000000ff);
+			*ptr++ = (uuid32_list[i] & 0x0000ff00) >> 8;
+			*ptr++ = (uuid32_list[i] & 0x00ff0000) >> 16;
+			*ptr++ = (uuid32_list[i] & 0xff000000) >> 24;
+		}
+
+		/* EIR Data length */
+		*length = (i * sizeof(u32)) + 1;
+
+		return ptr;
+	}
+
+	if (type == EIR_TYPE_UUID128) {
+
+		u8 *length = ptr;
+		u128 *uuid128_list = (u128 *) list;
+		u128 u;
+
+		memset(u.data, 0, sizeof(u128));
+		/* EIR Data type */
+		ptr[1] = truncated ? EIR_UUID128_SOME : EIR_UUID128_ALL;
+
+		ptr += 2;
+
+		i = 0;
+		while (memcmp(uuid128_list[i].data, u.data, sizeof(u128))) {
+
+			memcpy(ptr, uuid128_list[i].data, sizeof(u128));
+
+			ptr += sizeof(u128);
+			i++;
+		}
+
+		/* EIR Data length */
+		*length = (i * sizeof(u128)) + 1;
+
+		return ptr;
+
+	}
+
+	return ptr;
+}
+
 static void create_eir(struct hci_dev *hdev, u8 *data)
 {
 	u8 *ptr = data;
-- 
1.7.9.5


^ permalink raw reply related

* [RFC PATCH v0 2/6] Bluetooth: Add helper function to get the uuid type
From: Syam Sidhardhan @ 2013-01-24  5:57 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1359007079-11724-1-git-send-email-s.syam@samsung.com>

This function will return the particular uuid type

Signed-off-by: Syam Sidhardhan <s.syam@samsung.com>
Tested-by: Chan-yeol Park <chanyeol.park@samsung.com>
---
 net/bluetooth/mgmt.c |   21 +++++++++++++++++++++
 1 file changed, 21 insertions(+)

diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 4fd45a3..0f32986 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -37,6 +37,10 @@ bool enable_hs;
 #define MGMT_VERSION	1
 #define MGMT_REVISION	2
 
+#define EIR_TYPE_UUID16 1
+#define EIR_TYPE_UUID32 2
+#define EIR_TYPE_UUID128 3
+
 static const u16 mgmt_commands[] = {
 	MGMT_OP_READ_INDEX_LIST,
 	MGMT_OP_READ_INFO,
@@ -440,6 +444,23 @@ static u8 bluetooth_base_uuid[] = {
 			0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 };
 
+static int get_uuid_type(u8 *uuid128)
+{
+	u32 val;
+	int i;
+
+	for (i = 0; i < 12; i++) {
+		if (bluetooth_base_uuid[i] != uuid128[i])
+			return EIR_TYPE_UUID128;
+	}
+
+	val = get_unaligned_le32(&uuid128[12]);
+	if (val > 0xffff)
+		return EIR_TYPE_UUID32;
+	else
+		return EIR_TYPE_UUID16;
+}
+
 static u16 get_uuid16(u8 *uuid128)
 {
 	u32 val;
-- 
1.7.9.5


^ 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