Linux bluetooth development
 help / color / mirror / Atom feed
* [PATCH SBC v3 2/2] sbc: Add sbc_init_a2dp to sbc.sym
From: Luiz Augusto von Dentz @ 2014-01-20 19:34 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1390246452-29103-1-git-send-email-luiz.dentz@gmail.com>

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

---
 sbc/sbc.sym | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/sbc/sbc.sym b/sbc/sbc.sym
index 3a0c6bf..0c23a05 100644
--- a/sbc/sbc.sym
+++ b/sbc/sbc.sym
@@ -19,3 +19,7 @@ SBC_1.1 {
 global:
 	sbc_init_msbc;
 } SBC_1.0;
+SBC_1.2 {
+global:
+	sbc_init_a2dp;
+} SBC_1.1;
-- 
1.8.4.2


^ permalink raw reply related

* [PATCH SBC v3 1/2] sbc: Add sbc_init_a2dp
From: Luiz Augusto von Dentz @ 2014-01-20 19:34 UTC (permalink / raw)
  To: linux-bluetooth

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

This adds sbc_init_a2dp that can be used to convert A2DP configuration to
the internal representation since they are not binary compatible.
---
 sbc/sbc.c | 144 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 sbc/sbc.h |   2 +
 2 files changed, 146 insertions(+)

diff --git a/sbc/sbc.c b/sbc/sbc.c
index c589217..9fd2311 100644
--- a/sbc/sbc.c
+++ b/sbc/sbc.c
@@ -57,6 +57,55 @@
 #define MSBC_SYNCWORD	0xAD
 #define MSBC_BLOCKS	15
 
+#define A2DP_SAMPLING_FREQ_16000		(1 << 3)
+#define A2DP_SAMPLING_FREQ_32000		(1 << 2)
+#define A2DP_SAMPLING_FREQ_44100		(1 << 1)
+#define A2DP_SAMPLING_FREQ_48000		1
+
+#define A2DP_CHANNEL_MODE_MONO			(1 << 3)
+#define A2DP_CHANNEL_MODE_DUAL_CHANNEL		(1 << 2)
+#define A2DP_CHANNEL_MODE_STEREO		(1 << 1)
+#define A2DP_CHANNEL_MODE_JOINT_STEREO		1
+
+#define A2DP_BLOCK_LENGTH_4			(1 << 3)
+#define A2DP_BLOCK_LENGTH_8			(1 << 2)
+#define A2DP_BLOCK_LENGTH_12			(1 << 1)
+#define A2DP_BLOCK_LENGTH_16			1
+
+#define A2DP_SUBBANDS_4				(1 << 1)
+#define A2DP_SUBBANDS_8				1
+
+#define A2DP_ALLOCATION_SNR			(1 << 1)
+#define A2DP_ALLOCATION_LOUDNESS		1
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+
+struct a2dp_sbc {
+	uint8_t channel_mode:4;
+	uint8_t frequency:4;
+	uint8_t allocation_method:2;
+	uint8_t subbands:2;
+	uint8_t block_length:4;
+	uint8_t min_bitpool;
+	uint8_t max_bitpool;
+} __attribute__ ((packed));
+
+#elif __BYTE_ORDER == __BIG_ENDIAN
+
+struct a2dp_sbc {
+	uint8_t frequency:4;
+	uint8_t channel_mode:4;
+	uint8_t block_length:4;
+	uint8_t subbands:2;
+	uint8_t allocation_method:2;
+	uint8_t min_bitpool;
+	uint8_t max_bitpool;
+} __attribute__ ((packed));
+
+#else
+#error "Unknown byte order"
+#endif
+
 /* This structure contains an unpacked SBC frame.
    Yes, there is probably quite some unused space herein */
 struct sbc_frame {
@@ -1046,6 +1095,101 @@ SBC_EXPORT int sbc_init_msbc(sbc_t *sbc, unsigned long flags)
 	return 0;
 }
 
+SBC_EXPORT int sbc_init_a2dp(sbc_t *sbc, unsigned long flags, const void *conf,
+							size_t conf_len)
+{
+	const struct a2dp_sbc *a2dp;
+	int err;
+
+	if (conf_len != sizeof(*a2dp))
+		return -EINVAL;
+
+	err = sbc_init(sbc, flags);
+	if (err < 0)
+		return err;
+
+	a2dp = conf;
+
+	switch (a2dp->frequency) {
+	case A2DP_SAMPLING_FREQ_16000:
+		sbc->frequency = SBC_FREQ_16000;
+		break;
+	case A2DP_SAMPLING_FREQ_32000:
+		sbc->frequency = SBC_FREQ_32000;
+		break;
+	case A2DP_SAMPLING_FREQ_44100:
+		sbc->frequency = SBC_FREQ_44100;
+		break;
+	case A2DP_SAMPLING_FREQ_48000:
+		sbc->frequency = SBC_FREQ_48000;
+		break;
+	default:
+		goto failed;
+	}
+
+	switch (a2dp->channel_mode) {
+	case A2DP_CHANNEL_MODE_MONO:
+		sbc->mode = SBC_MODE_MONO;
+		break;
+	case A2DP_CHANNEL_MODE_DUAL_CHANNEL:
+		sbc->mode = SBC_MODE_DUAL_CHANNEL;
+		break;
+	case A2DP_CHANNEL_MODE_STEREO:
+		sbc->mode = SBC_MODE_STEREO;
+		break;
+	case A2DP_CHANNEL_MODE_JOINT_STEREO:
+		sbc->mode = SBC_MODE_JOINT_STEREO;
+		break;
+	default:
+		goto failed;
+	}
+
+	switch (a2dp->allocation_method) {
+	case A2DP_ALLOCATION_SNR:
+		sbc->allocation = SBC_AM_SNR;
+		break;
+	case A2DP_ALLOCATION_LOUDNESS:
+		sbc->allocation = SBC_AM_LOUDNESS;
+		break;
+	default:
+		goto failed;
+	}
+
+	switch (a2dp->subbands) {
+	case A2DP_SUBBANDS_4:
+		sbc->subbands = SBC_SB_4;
+		break;
+	case A2DP_SUBBANDS_8:
+		sbc->subbands = SBC_SB_8;
+		break;
+	default:
+		goto failed;
+	}
+
+	switch (a2dp->block_length) {
+	case A2DP_BLOCK_LENGTH_4:
+		sbc->blocks = SBC_BLK_4;
+		break;
+	case A2DP_BLOCK_LENGTH_8:
+		sbc->blocks = SBC_BLK_8;
+		break;
+	case A2DP_BLOCK_LENGTH_12:
+		sbc->blocks = SBC_BLK_12;
+		break;
+	case A2DP_BLOCK_LENGTH_16:
+		sbc->blocks = SBC_BLK_16;
+		break;
+	default:
+		goto failed;
+	}
+
+	return 0;
+
+failed:
+	sbc_finish(sbc);
+	return -EINVAL;
+}
+
 SBC_EXPORT ssize_t sbc_parse(sbc_t *sbc, const void *input, size_t input_len)
 {
 	return sbc_decode(sbc, input, input_len, NULL, 0, NULL);
diff --git a/sbc/sbc.h b/sbc/sbc.h
index 5f8a1fc..02ad9fe 100644
--- a/sbc/sbc.h
+++ b/sbc/sbc.h
@@ -84,6 +84,8 @@ typedef struct sbc_struct sbc_t;
 int sbc_init(sbc_t *sbc, unsigned long flags);
 int sbc_reinit(sbc_t *sbc, unsigned long flags);
 int sbc_init_msbc(sbc_t *sbc, unsigned long flags);
+int sbc_init_a2dp(sbc_t *sbc, unsigned long flags, const void *conf,
+							size_t conf_len);
 
 ssize_t sbc_parse(sbc_t *sbc, const void *input, size_t input_len);
 
-- 
1.8.4.2


^ permalink raw reply related

* Re: [PATCH] obexd/irmc: Fix folder for LUID requests
From: Luiz Augusto von Dentz @ 2014-01-20 19:29 UTC (permalink / raw)
  To: Harald Schmitt; +Cc: linux-bluetooth@vger.kernel.org
In-Reply-To: <1390239558-6384-1-git-send-email-linux@hschmitt.de>

Hi Harald,

On Mon, Jan 20, 2014 at 7:39 PM, Harald Schmitt <linux@hschmitt.de> wrote:
> The old macro PB_LUID_FOLDER had the folder luid on the second level:
> /telecom/luid. But the luid folder occurs per IrMC spec on level three e.g.
> /telecom/pb/luid. On the second level the object store e.g. pb is specified.
> This bug was introduced with commit 62ebf8d0f345e7722334d852cf7a010b202647e7.
> ---
>  obexd/plugins/irmc.c      | 6 +++---
>  obexd/plugins/phonebook.h | 2 +-
>  2 files changed, 4 insertions(+), 4 deletions(-)
>
> diff --git a/obexd/plugins/irmc.c b/obexd/plugins/irmc.c
> index d343977..d0e98b4 100644
> --- a/obexd/plugins/irmc.c
> +++ b/obexd/plugins/irmc.c
> @@ -326,7 +326,7 @@ static int irmc_open_nt(struct irmc_session *irmc)
>         return 0;
>  }
>
> -static int irmc_open_luid(struct irmc_session *irmc)
> +static int irmc_open_pb_luid(struct irmc_session *irmc)
>  {
>         if (irmc->buffer == NULL)
>                 irmc->buffer = g_string_new("");
> @@ -381,8 +381,8 @@ static void *irmc_open(const char *name, int oflag, mode_t mode, void *context,
>                 ret = irmc_open_cal(irmc);
>         else if (g_str_has_prefix(path, PB_NOTES_FOLDER))
>                 ret = irmc_open_nt(irmc);
> -       else if (g_str_has_prefix(path, PB_LUID_FOLDER))
> -               ret = irmc_open_luid(irmc);
> +       else if (g_str_has_prefix(path, PB_CONTACTS_LUID_FOLDER))
> +               ret = irmc_open_pb_luid(irmc);
>         else
>                 ret = -EBADR;
>
> diff --git a/obexd/plugins/phonebook.h b/obexd/plugins/phonebook.h
> index 441cff2..015c9a3 100644
> --- a/obexd/plugins/phonebook.h
> +++ b/obexd/plugins/phonebook.h
> @@ -37,7 +37,7 @@
>  #define PB_CALLS_INCOMING_FOLDER "/telecom/ich"
>  #define PB_CALLS_MISSED_FOLDER "/telecom/mch"
>  #define PB_CALLS_OUTGOING_FOLDER "/telecom/och"
> -#define PB_LUID_FOLDER "/telecom/luid"
> +#define PB_CONTACTS_LUID_FOLDER "/telecom/pb/luid"
>
>  #define PB_CONTACTS "/telecom/pb.vcf"
>  #define PB_CALLS_COMBINED "/telecom/cch.vcf"
> --
> 1.8.3.2

I went ahead and pushed this one, but I preserve much of the define
and function names used before since I did not see any reason to
change those.


-- 
Luiz Augusto von Dentz

^ permalink raw reply

* [PATCH SBC v2 2/2] sbc: Add sbc_init_a2dp to sbc.sym
From: Luiz Augusto von Dentz @ 2014-01-20 18:51 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1390243913-13962-1-git-send-email-luiz.dentz@gmail.com>

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

---
 sbc/sbc.sym | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/sbc/sbc.sym b/sbc/sbc.sym
index 3a0c6bf..0c23a05 100644
--- a/sbc/sbc.sym
+++ b/sbc/sbc.sym
@@ -19,3 +19,7 @@ SBC_1.1 {
 global:
 	sbc_init_msbc;
 } SBC_1.0;
+SBC_1.2 {
+global:
+	sbc_init_a2dp;
+} SBC_1.1;
-- 
1.8.4.2


^ permalink raw reply related

* [PATCH SBC v2 1/2] sbc: Add sbc_init_a2dp
From: Luiz Augusto von Dentz @ 2014-01-20 18:51 UTC (permalink / raw)
  To: linux-bluetooth

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

This adds sbc_init_a2dp that can be used to convert A2DP configuration to
the internal representation since they are not binary compatible.
---
 sbc/sbc.c | 144 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 sbc/sbc.h |   2 +
 2 files changed, 146 insertions(+)

diff --git a/sbc/sbc.c b/sbc/sbc.c
index c589217..9352446 100644
--- a/sbc/sbc.c
+++ b/sbc/sbc.c
@@ -57,6 +57,55 @@
 #define MSBC_SYNCWORD	0xAD
 #define MSBC_BLOCKS	15
 
+#define A2DP_SAMPLING_FREQ_16000		(1 << 3)
+#define A2DP_SAMPLING_FREQ_32000		(1 << 2)
+#define A2DP_SAMPLING_FREQ_44100		(1 << 1)
+#define A2DP_SAMPLING_FREQ_48000		1
+
+#define A2DP_CHANNEL_MODE_MONO			(1 << 3)
+#define A2DP_CHANNEL_MODE_DUAL_CHANNEL		(1 << 2)
+#define A2DP_CHANNEL_MODE_STEREO		(1 << 1)
+#define A2DP_CHANNEL_MODE_JOINT_STEREO		1
+
+#define A2DP_BLOCK_LENGTH_4			(1 << 3)
+#define A2DP_BLOCK_LENGTH_8			(1 << 2)
+#define A2DP_BLOCK_LENGTH_12			(1 << 1)
+#define A2DP_BLOCK_LENGTH_16			1
+
+#define A2DP_SUBBANDS_4				(1 << 1)
+#define A2DP_SUBBANDS_8				1
+
+#define A2DP_ALLOCATION_SNR			(1 << 1)
+#define A2DP_ALLOCATION_LOUDNESS		1
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+
+struct a2dp_sbc {
+	uint8_t channel_mode:4;
+	uint8_t frequency:4;
+	uint8_t allocation_method:2;
+	uint8_t subbands:2;
+	uint8_t block_length:4;
+	uint8_t min_bitpool;
+	uint8_t max_bitpool;
+} __attribute__ ((packed));
+
+#elif __BYTE_ORDER == __BIG_ENDIAN
+
+struct a2dp_sbc {
+	uint8_t frequency:4;
+	uint8_t channel_mode:4;
+	uint8_t block_length:4;
+	uint8_t subbands:2;
+	uint8_t allocation_method:2;
+	uint8_t min_bitpool;
+	uint8_t max_bitpool;
+} __attribute__ ((packed));
+
+#else
+#error "Unknown byte order"
+#endif
+
 /* This structure contains an unpacked SBC frame.
    Yes, there is probably quite some unused space herein */
 struct sbc_frame {
@@ -1046,6 +1095,101 @@ SBC_EXPORT int sbc_init_msbc(sbc_t *sbc, unsigned long flags)
 	return 0;
 }
 
+SBC_EXPORT int sbc_init_a2dp(sbc_t *sbc, unsigned long flags,
+						const void *config, size_t len)
+{
+	const struct a2dp_sbc *a2dp;
+	int err;
+
+	if (len != sizeof(*a2dp))
+		return -EINVAL;
+
+	err = sbc_init(sbc, flags);
+	if (err < 0)
+		return err;
+
+	a2dp = config;
+
+	switch (a2dp->frequency) {
+	case A2DP_SAMPLING_FREQ_16000:
+		sbc->frequency = SBC_FREQ_16000;
+		break;
+	case A2DP_SAMPLING_FREQ_32000:
+		sbc->frequency = SBC_FREQ_32000;
+		break;
+	case A2DP_SAMPLING_FREQ_44100:
+		sbc->frequency = SBC_FREQ_44100;
+		break;
+	case A2DP_SAMPLING_FREQ_48000:
+		sbc->frequency = SBC_FREQ_48000;
+		break;
+	default:
+		goto failed;
+	}
+
+	switch (a2dp->channel_mode) {
+	case A2DP_CHANNEL_MODE_MONO:
+		sbc->mode = SBC_MODE_MONO;
+		break;
+	case A2DP_CHANNEL_MODE_DUAL_CHANNEL:
+		sbc->mode = SBC_MODE_DUAL_CHANNEL;
+		break;
+	case A2DP_CHANNEL_MODE_STEREO:
+		sbc->mode = SBC_MODE_STEREO;
+		break;
+	case A2DP_CHANNEL_MODE_JOINT_STEREO:
+		sbc->mode = SBC_MODE_JOINT_STEREO;
+		break;
+	default:
+		goto failed;
+	}
+
+	switch (a2dp->allocation_method) {
+	case A2DP_ALLOCATION_SNR:
+		sbc->allocation = SBC_AM_SNR;
+		break;
+	case A2DP_ALLOCATION_LOUDNESS:
+		sbc->allocation = SBC_AM_LOUDNESS;
+		break;
+	default:
+		goto failed;
+	}
+
+	switch (a2dp->subbands) {
+	case A2DP_SUBBANDS_4:
+		sbc->subbands = SBC_SB_4;
+		break;
+	case A2DP_SUBBANDS_8:
+		sbc->subbands = SBC_SB_8;
+		break;
+	default:
+		goto failed;
+	}
+
+	switch (a2dp->block_length) {
+	case A2DP_BLOCK_LENGTH_4:
+		sbc->blocks = SBC_BLK_4;
+		break;
+	case A2DP_BLOCK_LENGTH_8:
+		sbc->blocks = SBC_BLK_8;
+		break;
+	case A2DP_BLOCK_LENGTH_12:
+		sbc->blocks = SBC_BLK_12;
+		break;
+	case A2DP_BLOCK_LENGTH_16:
+		sbc->blocks = SBC_BLK_16;
+		break;
+	default:
+		goto failed;
+	}
+
+	return 0;
+
+failed:
+	sbc_finish(sbc);
+	return -EINVAL;
+}
+
 SBC_EXPORT ssize_t sbc_parse(sbc_t *sbc, const void *input, size_t input_len)
 {
 	return sbc_decode(sbc, input, input_len, NULL, 0, NULL);
diff --git a/sbc/sbc.h b/sbc/sbc.h
index 5f8a1fc..5791faa 100644
--- a/sbc/sbc.h
+++ b/sbc/sbc.h
@@ -84,6 +84,8 @@ typedef struct sbc_struct sbc_t;
 int sbc_init(sbc_t *sbc, unsigned long flags);
 int sbc_reinit(sbc_t *sbc, unsigned long flags);
 int sbc_init_msbc(sbc_t *sbc, unsigned long flags);
+int sbc_init_a2dp(sbc_t *sbc, unsigned long flags, const void *config,
+								size_t len);
 
 ssize_t sbc_parse(sbc_t *sbc, const void *input, size_t input_len);
 
-- 
1.8.4.2


^ permalink raw reply related

* Re: [PATCH v2 1/5] lib: Add flag to force large MTU size used for SDP connection
From: Szymon Janc @ 2014-01-20 18:48 UTC (permalink / raw)
  To: simon; +Cc: Szymon Janc, linux-bluetooth
In-Reply-To: <cfdf976e52d86b180ee5e750c23fed8f.squirrel@mungewell.org>

Hi Simon,

On Monday 20 January 2014 13:28:57 simon@mungewell.org wrote:
> > From: Szymon Janc <szymon.janc@gmail.com>
> > 
> > This will allow to workaround Dualshock4 not respecting L2CAP MTU
> > size while sending SDP response. Use same L2CAP MTU value base on
> > RFCOMM.
> 
> I can confirm that the V2 series of patches work with my DS4 and crappy
> laptop. Still require particular 'connect' sequence...

Thanks for testing, and yes this sequence is about dedicated vs general 
bonding mentioned in commit message.

> 
> I note that I do not need the original '[PATCH 3/3] input: Add DualShock 4
> detection' patch. I am using just this sequence of 5 patches on top of
> 5.13.

This detection is used only when using SSP controller. And only in case when 
dedicated bonding is used - when DS4 tries to connect immediately after 
pairing is completed, but before bluetoothd was able to retrieve SDP.

-- 
Szymon K. Janc
szymon.janc@gmail.com

^ permalink raw reply

* Re: [PATCH v2 1/5] lib: Add flag to force large MTU size used for SDP connection
From: simon @ 2014-01-20 18:28 UTC (permalink / raw)
  To: Szymon Janc; +Cc: linux-bluetooth, Szymon Janc
In-Reply-To: <1390216116-23670-1-git-send-email-szymon.janc@tieto.com>

> From: Szymon Janc <szymon.janc@gmail.com>
>
> This will allow to workaround Dualshock4 not respecting L2CAP MTU
> size while sending SDP response. Use same L2CAP MTU value base on
> RFCOMM.

I can confirm that the V2 series of patches work with my DS4 and crappy
laptop. Still require particular 'connect' sequence...

I note that I do not need the original '[PATCH 3/3] input: Add DualShock 4
detection' patch. I am using just this sequence of 5 patches on top of
5.13.
Simon



^ permalink raw reply

* Re: [PATCH 00/11] HIDHost E2E tests and fixes
From: Ravi kumar Veeramally @ 2014-01-20 18:08 UTC (permalink / raw)
  To: Szymon Janc; +Cc: linux-bluetooth
In-Reply-To: <1991876.SYBil5rWd4@uw000953>

Hi Szymon,

On 01/20/2014 05:30 PM, Szymon Janc wrote:
>   android/android-tester.c | 517 ++++++++++++++++++++++++++++++++++++++++++++++-
>   android/hal-hidhost.c    |   3 +-
>   android/hidhost.c        |  14 +-
>   3 files changed, 511 insertions(+), 23 deletions(-)
>
>
> I've applied all patches except 2 and 9, thanks.
> Please see comments for 02/11.
>
Ok, I will check what went wrong.

Thanks,
Ravi.

^ permalink raw reply

* [PATCH BlueZ v1 18/18] bluetooth.conf: Add ObjectManager interface
From: Claudio Takahasi @ 2014-01-20 18:05 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: claudio.takahasi
In-Reply-To: <1390241103-808-1-git-send-email-claudio.takahasi@openbossa.org>

---
 src/bluetooth.conf | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/bluetooth.conf b/src/bluetooth.conf
index 0495200..ad8891a 100644
--- a/src/bluetooth.conf
+++ b/src/bluetooth.conf
@@ -18,6 +18,7 @@
     <allow send_interface="org.bluez.Profile1"/>
     <allow send_interface="org.bluez.HeartRateWatcher1"/>
     <allow send_interface="org.bluez.CyclingSpeedWatcher1"/>
+    <allow send_interface="org.freedesktop.DBus.ObjectManager"/>
   </policy>
 
   <policy at_console="true">
-- 
1.8.3.1


^ permalink raw reply related

* [PATCH BlueZ v1 17/18] gatttool: Add unix socket support for interactive mode
From: Claudio Takahasi @ 2014-01-20 18:05 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: claudio.takahasi
In-Reply-To: <1390241103-808-1-git-send-email-claudio.takahasi@openbossa.org>

This patch allows running GATT operations over unix socket on
interactive mode.
---
 attrib/interactive.c | 19 +++++++++++--------
 1 file changed, 11 insertions(+), 8 deletions(-)

diff --git a/attrib/interactive.c b/attrib/interactive.c
index 9826a4b..febebaa 100644
--- a/attrib/interactive.c
+++ b/attrib/interactive.c
@@ -84,7 +84,7 @@ static char *get_prompt(void)
 	if (opt_dst)
 		g_string_append_printf(prompt, "[%17s]", opt_dst);
 	else
-		g_string_append_printf(prompt, "[%17s]", "");
+		g_string_append_printf(prompt, "[LOCAL]");
 
 	if (conn_state == STATE_CONNECTED)
 		g_string_append(prompt, COLOR_OFF);
@@ -405,15 +405,18 @@ static void cmd_connect(int argcp, char **argvp)
 			opt_dst_type = g_strdup("public");
 	}
 
-	if (opt_dst == NULL) {
-		error("Remote Bluetooth address required\n");
-		return;
+	if (opt_dst) {
+
+		rl_printf("Attempting to connect to %s\n", opt_dst);
+		set_state(STATE_CONNECTING);
+		iochannel = gatt_connect(opt_src, opt_dst, opt_dst_type,
+					opt_sec_level, opt_psm, opt_mtu,
+					connect_cb, &gerr);
+	} else {
+		rl_printf("Local connection\n");
+		iochannel = unix_connect(connect_cb, &gerr);
 	}
 
-	rl_printf("Attempting to connect to %s\n", opt_dst);
-	set_state(STATE_CONNECTING);
-	iochannel = gatt_connect(opt_src, opt_dst, opt_dst_type, opt_sec_level,
-					opt_psm, opt_mtu, connect_cb, &gerr);
 	if (iochannel == NULL) {
 		set_state(STATE_DISCONNECTED);
 		error("%s\n", gerr->message);
-- 
1.8.3.1


^ permalink raw reply related

* [PATCH BlueZ v1 16/18] gatttool: Add unix socket connect
From: Claudio Takahasi @ 2014-01-20 18:05 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: claudio.takahasi
In-Reply-To: <1390241103-808-1-git-send-email-claudio.takahasi@openbossa.org>

This patch adds the initial support for GATT procedures over unix
socket transport on command line mode (one-shot command). Temporary
solution to allow local GATT procedures testing.
---
 attrib/gatttool.c | 27 ++++++++++++++++++++-------
 attrib/gatttool.h |  1 +
 attrib/utils.c    | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 75 insertions(+), 7 deletions(-)

diff --git a/attrib/gatttool.c b/attrib/gatttool.c
index ebc8123..d701f7b 100644
--- a/attrib/gatttool.c
+++ b/attrib/gatttool.c
@@ -29,7 +29,6 @@
 #include <errno.h>
 #include <glib.h>
 #include <stdlib.h>
-#include <unistd.h>
 
 #include <bluetooth/bluetooth.h>
 #include <bluetooth/hci.h>
@@ -53,6 +52,7 @@ static int opt_end = 0xffff;
 static int opt_handle = -1;
 static int opt_mtu = 0;
 static int opt_psm = 0;
+static gboolean opt_local = FALSE;
 static gboolean opt_primary = FALSE;
 static gboolean opt_characteristics = FALSE;
 static gboolean opt_char_read = FALSE;
@@ -511,6 +511,8 @@ static GOptionEntry options[] = {
 		"Specify local adapter interface", "hciX" },
 	{ "device", 'b', 0, G_OPTION_ARG_STRING, &opt_dst,
 		"Specify remote Bluetooth address", "MAC" },
+	{ "local", 'L', 0, G_OPTION_ARG_NONE, &opt_local,
+		"Use unix socket transport (local communication)", NULL },
 	{ "addr-type", 't', 0, G_OPTION_ARG_STRING, &opt_dst_type,
 		"Set LE address type. Default: public", "[public | random]"},
 	{ "mtu", 'm', 0, G_OPTION_ARG_INT, &opt_mtu,
@@ -563,6 +565,11 @@ int main(int argc, char *argv[])
 		g_clear_error(&gerr);
 	}
 
+	if (opt_local) {
+		opt_src = NULL;
+		opt_dst = NULL;
+	}
+
 	if (opt_interactive) {
 		interactive(opt_src, opt_dst, opt_dst_type, opt_psm);
 		goto done;
@@ -588,14 +595,20 @@ int main(int argc, char *argv[])
 		goto done;
 	}
 
-	if (opt_dst == NULL) {
-		g_print("Remote Bluetooth address required\n");
-		got_error = TRUE;
-		goto done;
+	if (opt_local)
+		chan = unix_connect(connect_cb, &gerr);
+	else {
+		if (opt_dst == NULL) {
+			g_print("Remote Bluetooth address required\n");
+			got_error = TRUE;
+			goto done;
+		}
+
+		chan = gatt_connect(opt_src, opt_dst, opt_dst_type,
+					opt_sec_level, opt_psm, opt_mtu,
+					connect_cb, &gerr);
 	}
 
-	chan = gatt_connect(opt_src, opt_dst, opt_dst_type, opt_sec_level,
-					opt_psm, opt_mtu, connect_cb, &gerr);
 	if (chan == NULL) {
 		g_printerr("%s\n", gerr->message);
 		g_clear_error(&gerr);
diff --git a/attrib/gatttool.h b/attrib/gatttool.h
index 8f0913c..be8e236 100644
--- a/attrib/gatttool.h
+++ b/attrib/gatttool.h
@@ -27,4 +27,5 @@ GIOChannel *gatt_connect(const char *src, const char *dst,
 			const char *dst_type, const char *sec_level,
 			int psm, int mtu, BtIOConnect connect_cb,
 			GError **gerr);
+GIOChannel *unix_connect(BtIOConnect connect_cb, GError **gerr);
 size_t gatt_attr_data_from_string(const char *str, uint8_t **data);
diff --git a/attrib/utils.c b/attrib/utils.c
index 77bab27..de7b00a 100644
--- a/attrib/utils.c
+++ b/attrib/utils.c
@@ -25,7 +25,12 @@
 #include "config.h"
 #endif
 
+#include <errno.h>
 #include <stdlib.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
 #include <glib.h>
 
 #include <bluetooth/bluetooth.h>
@@ -101,6 +106,55 @@ GIOChannel *gatt_connect(const char *src, const char *dst,
 	return chan;
 }
 
+static gboolean unix_connect_cb(GIOChannel *io, GIOCondition cond,
+							gpointer user_data)
+{
+	BtIOConnect connect_cb = user_data;
+	GError *gerr;
+
+	if (cond & (G_IO_HUP | G_IO_ERR | G_IO_NVAL)) {
+		gerr = g_error_new_literal(G_IO_CHANNEL_ERROR,
+						G_IO_CHANNEL_ERROR_FAILED,
+						"connection attempt failed");
+		connect_cb(io, gerr, user_data);
+		g_clear_error(&gerr);
+	} else {
+		connect_cb(io, NULL, user_data);
+	}
+
+	return FALSE;
+}
+
+GIOChannel *unix_connect(BtIOConnect connect_cb, GError **gerr)
+{
+	GIOChannel *io;
+	struct sockaddr_un uaddr  = {
+		.sun_family	= AF_UNIX,
+		.sun_path	= "\0/bluetooth/unix_att",
+	};
+	int sk;
+
+	sk = socket(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC , 0);
+	if (sk < 0) {
+		g_set_error_literal(gerr, G_IO_CHANNEL_ERROR,
+				G_IO_CHANNEL_ERROR_FAILED, strerror(errno));
+		return NULL;
+	}
+
+	if (connect(sk, (struct sockaddr *) &uaddr, sizeof(uaddr)) < 0) {
+		g_set_error_literal(gerr, G_IO_CHANNEL_ERROR,
+				G_IO_CHANNEL_ERROR_FAILED, strerror(errno));
+		close(sk);
+		return NULL;
+	}
+
+	io = g_io_channel_unix_new(sk);
+	g_io_add_watch(io, G_IO_OUT | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
+						unix_connect_cb, connect_cb);
+
+	return io;
+}
+
 size_t gatt_attr_data_from_string(const char *str, uint8_t **data)
 {
 	char tmp[3];
-- 
1.8.3.1


^ permalink raw reply related

* [PATCH BlueZ v1 15/18] test: Add registering external service
From: Claudio Takahasi @ 2014-01-20 18:05 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: claudio.takahasi
In-Reply-To: <1390241103-808-1-git-send-email-claudio.takahasi@openbossa.org>

This patch extends gatt-service to call RegisterService() when org.bluez
service gets connected to the system bus.
---
 test/gatt-service.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 66 insertions(+)

diff --git a/test/gatt-service.c b/test/gatt-service.c
index c076588..dc00f4c 100644
--- a/test/gatt-service.c
+++ b/test/gatt-service.c
@@ -114,6 +114,65 @@ static void create_services(DBusConnection *conn)
 	printf("Registered service: %s\n", service_path);
 }
 
+static void register_external_service_reply(DBusPendingCall *call,
+							void *user_data)
+{
+	DBusMessage *reply = dbus_pending_call_steal_reply(call);
+	DBusError derr;
+
+	dbus_error_init(&derr);
+	dbus_set_error_from_message(&derr, reply);
+
+	if (dbus_error_is_set(&derr))
+		fprintf(stderr, "RegisterService: %s\n", derr.message);
+	else
+		printf("RegisterService: OK\n");
+
+	dbus_message_unref(reply);
+	dbus_error_free(&derr);
+}
+
+static void register_external_service(gpointer a, gpointer b)
+{
+	DBusConnection *conn = b;
+	const char *path = a;
+	DBusMessage *msg;
+	DBusPendingCall *call;
+	DBusMessageIter iter, dict;
+
+	msg = dbus_message_new_method_call("org.bluez", "/org/bluez",
+					SERVICE_MGR_IFACE, "RegisterService");
+	if (msg == NULL) {
+		fprintf(stderr, "Couldn't allocate D-Bus message\n");
+		return;
+	}
+
+	dbus_message_iter_init_append(msg, &iter);
+
+	dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH, &path);
+
+	dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{sv}", &dict);
+
+	/* TODO: Add options dictionary */
+
+	dbus_message_iter_close_container(&iter, &dict);
+
+	if (g_dbus_send_message_with_reply(conn, msg, &call, -1) == FALSE) {
+		dbus_message_unref(msg);
+		return;
+	}
+
+	dbus_pending_call_set_notify(call, register_external_service_reply,
+								NULL, NULL);
+
+	dbus_pending_call_unref(call);
+}
+
+static void connect_handler(DBusConnection *conn, void *user_data)
+{
+	g_slist_foreach(services, register_external_service, conn);
+}
+
 static gboolean signal_handler(GIOChannel *channel, GIOCondition condition,
 							gpointer user_data)
 {
@@ -159,6 +218,7 @@ static guint setup_signalfd(void)
 
 int main(int argc, char *argv[])
 {
+	GDBusClient *client;
 	DBusConnection *dbus_conn;
 	guint signal;
 
@@ -177,8 +237,14 @@ int main(int argc, char *argv[])
 
 	create_services(dbus_conn);
 
+	client = g_dbus_client_new(dbus_conn, "org.bluez", "/org/bluez");
+
+	g_dbus_client_set_connect_watch(client, connect_handler, NULL);
+
 	g_main_loop_run(main_loop);
 
+	g_dbus_client_unref(client);
+
 	g_source_remove(signal);
 
 	g_slist_free_full(services, g_free);
-- 
1.8.3.1


^ permalink raw reply related

* [PATCH BlueZ v1 14/18] test: Add signal handling for gatt-service
From: Claudio Takahasi @ 2014-01-20 18:04 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: claudio.takahasi
In-Reply-To: <1390241103-808-1-git-send-email-claudio.takahasi@openbossa.org>

This patch implements signal handling to run cleanup tasks before
exiting.
---
 test/gatt-service.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 52 insertions(+)

diff --git a/test/gatt-service.c b/test/gatt-service.c
index 16e2cea..c076588 100644
--- a/test/gatt-service.c
+++ b/test/gatt-service.c
@@ -27,12 +27,14 @@
 
 #include <errno.h>
 #include <stdio.h>
+#include <sys/signalfd.h>
 
 #include <glib.h>
 #include <dbus/dbus.h>
 #include <gdbus/gdbus.h>
 
 #define SERVICE_IFACE			"org.bluez.Service1"
+#define SERVICE_MGR_IFACE		"org.bluez.ServiceManager1"
 
 /* Immediate Alert Service UUID */
 #define IAS_UUID			"00001802-0000-1000-8000-00805f9b34fb"
@@ -112,9 +114,57 @@ static void create_services(DBusConnection *conn)
 	printf("Registered service: %s\n", service_path);
 }
 
+static gboolean signal_handler(GIOChannel *channel, GIOCondition condition,
+							gpointer user_data)
+{
+	g_main_loop_quit(main_loop);
+
+	return FALSE;
+}
+
+static guint setup_signalfd(void)
+{
+	GIOChannel *channel;
+	guint source;
+	sigset_t mask;
+	int fd;
+
+	sigemptyset(&mask);
+	sigaddset(&mask, SIGINT);
+	sigaddset(&mask, SIGTERM);
+
+	if (sigprocmask(SIG_BLOCK, &mask, NULL) < 0) {
+		perror("Failed to set signal mask");
+		return 0;
+	}
+
+	fd = signalfd(-1, &mask, 0);
+	if (fd < 0) {
+		perror("Failed to create signal descriptor");
+		return 0;
+	}
+
+	channel = g_io_channel_unix_new(fd);
+
+	g_io_channel_set_close_on_unref(channel, TRUE);
+
+	source = g_io_add_watch(channel,
+				G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+				signal_handler, NULL);
+
+	g_io_channel_unref(channel);
+
+	return source;
+}
+
 int main(int argc, char *argv[])
 {
 	DBusConnection *dbus_conn;
+	guint signal;
+
+	signal = setup_signalfd();
+	if (signal == 0)
+		return -errno;
 
 	dbus_conn = g_dbus_setup_bus(DBUS_BUS_SYSTEM, NULL, NULL);
 
@@ -129,6 +179,8 @@ int main(int argc, char *argv[])
 
 	g_main_loop_run(main_loop);
 
+	g_source_remove(signal);
+
 	g_slist_free_full(services, g_free);
 	dbus_connection_unref(dbus_conn);
 
-- 
1.8.3.1


^ permalink raw reply related

* [PATCH BlueZ v1 13/18] gitignore: Add test/gatt-service
From: Claudio Takahasi @ 2014-01-20 18:04 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: claudio.takahasi
In-Reply-To: <1390241103-808-1-git-send-email-claudio.takahasi@openbossa.org>

---
 .gitignore | 1 +
 1 file changed, 1 insertion(+)

diff --git a/.gitignore b/.gitignore
index 2c8e033..82f99ba 100644
--- a/.gitignore
+++ b/.gitignore
@@ -73,6 +73,7 @@ tools/3dsp
 tools/obexctl
 test/sap_client.pyc
 test/bluezutils.pyc
+test/gatt-service
 unit/test-eir
 unit/test-uuid
 unit/test-crc
-- 
1.8.3.1


^ permalink raw reply related

* [PATCH BlueZ v1 12/18] test: Add external service GATT skeleton
From: Claudio Takahasi @ 2014-01-20 18:04 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: claudio.takahasi
In-Reply-To: <1390241103-808-1-git-send-email-claudio.takahasi@openbossa.org>

This patch adds the initial code for an external GATT service example.
It implements the API defined at doc/gatt-api.txt
---
 Makefile.tools      |   5 ++
 test/gatt-service.c | 136 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 141 insertions(+)
 create mode 100644 test/gatt-service.c

diff --git a/Makefile.tools b/Makefile.tools
index 7548dca..2a80962 100644
--- a/Makefile.tools
+++ b/Makefile.tools
@@ -367,3 +367,8 @@ test_scripts += test/sap_client.py test/bluezutils.py \
 		test/test-heartrate test/test-alert test/test-hfp \
 		test/test-cyclingspeed test/opp-client test/ftp-client \
 		test/pbap-client test/map-client
+
+noinst_PROGRAMS += test/gatt-service
+
+test_gatt_service_SOURCES = test/gatt-service.c
+test_gatt_service_LDADD = @GLIB_LIBS@ @DBUS_LIBS@ gdbus/libgdbus-internal.la
diff --git a/test/gatt-service.c b/test/gatt-service.c
new file mode 100644
index 0000000..16e2cea
--- /dev/null
+++ b/test/gatt-service.c
@@ -0,0 +1,136 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2013  Instituto Nokia de Tecnologia - INdT
+ *
+ *
+ *  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 <errno.h>
+#include <stdio.h>
+
+#include <glib.h>
+#include <dbus/dbus.h>
+#include <gdbus/gdbus.h>
+
+#define SERVICE_IFACE			"org.bluez.Service1"
+
+/* Immediate Alert Service UUID */
+#define IAS_UUID			"00001802-0000-1000-8000-00805f9b34fb"
+
+static GMainLoop *main_loop;
+static GSList *services;
+
+static gboolean service_get_uuid(const GDBusPropertyTable *property,
+					DBusMessageIter *iter, void *user_data)
+{
+	const char *uuid = user_data;
+
+	dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &uuid);
+
+	return TRUE;
+}
+
+static gboolean service_get_includes(const GDBusPropertyTable *property,
+					DBusMessageIter *iter, void *user_data)
+{
+	return TRUE;
+}
+
+static gboolean service_exist_includes(const GDBusPropertyTable *property,
+							void *user_data)
+{
+	return FALSE;
+}
+
+static DBusMessage *service_release(DBusConnection *conn,
+				DBusMessage *msg, void *user_data)
+{
+	fprintf(stderr, "Terminating...\n");
+
+	g_main_loop_quit(main_loop);
+
+	return NULL;
+}
+
+static const GDBusMethodTable service_methods[] = {
+	{ GDBUS_NOREPLY_METHOD("Release", NULL, NULL, service_release) },
+	{ }
+};
+
+static const GDBusPropertyTable service_properties[] = {
+	{ "UUID", "s", service_get_uuid },
+	{ "Includes", "ao", service_get_includes, NULL,
+					service_exist_includes },
+	{ }
+};
+
+static char *register_service(DBusConnection *conn, const char *uuid)
+{
+	static int id = 1;
+	char *path;
+
+	path = g_strdup_printf("/service%d", id++);
+	if (g_dbus_register_interface(conn, path, SERVICE_IFACE,
+				service_methods, NULL, service_properties,
+				g_strdup(uuid), g_free) == FALSE) {
+		fprintf(stderr, "Couldn't register service interface\n");
+		g_free(path);
+		return NULL;
+	}
+
+	return path;
+}
+
+static void create_services(DBusConnection *conn)
+{
+	char *service_path;
+
+	service_path = register_service(conn, IAS_UUID);
+
+	services = g_slist_prepend(services, service_path);
+
+	printf("Registered service: %s\n", service_path);
+}
+
+int main(int argc, char *argv[])
+{
+	DBusConnection *dbus_conn;
+
+	dbus_conn = g_dbus_setup_bus(DBUS_BUS_SYSTEM, NULL, NULL);
+
+	main_loop = g_main_loop_new(NULL, FALSE);
+
+	g_dbus_attach_object_manager(dbus_conn);
+
+	printf("gatt-service unique name: %s\n",
+				dbus_bus_get_unique_name(dbus_conn));
+
+	create_services(dbus_conn);
+
+	g_main_loop_run(main_loop);
+
+	g_slist_free_full(services, g_free);
+	dbus_connection_unref(dbus_conn);
+
+	return 0;
+}
-- 
1.8.3.1


^ permalink raw reply related

* [PATCH BlueZ v1 11/18] gatt: Add Discover All Primary Services
From: Claudio Takahasi @ 2014-01-20 18:04 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: claudio.takahasi, Alvaro Silva
In-Reply-To: <1390241103-808-1-git-send-email-claudio.takahasi@openbossa.org>

From: Alvaro Silva <alvaro.silva@openbossa.org>

This patch adds ATT Read By Group request handling to the attribute
server. It is the primitive to implement Discover All Primary Services
procedure.
---
 src/gatt.c | 129 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 128 insertions(+), 1 deletion(-)

diff --git a/src/gatt.c b/src/gatt.c
index 33c3b6a..b204f9c 100644
--- a/src/gatt.c
+++ b/src/gatt.c
@@ -112,6 +112,130 @@ static void send_error(GAttrib *attrib, uint8_t opcode, uint16_t handle,
 	g_attrib_send(attrib, 0, pdu, plen, NULL, NULL, NULL);
 }
 
+static void read_by_group_resp(GAttrib *attrib, uint16_t start,
+					uint16_t end, bt_uuid_t *pattern)
+{
+	uint8_t opdu[ATT_DEFAULT_LE_MTU];
+	GList *list;
+	struct btd_attribute *last = NULL;
+	uint8_t *group_start, *group_end = NULL, *group_uuid;
+	unsigned int uuid_type = BT_UUID_UNSPEC;
+	size_t group_len = 0, plen = 0;
+
+	/*
+	 * Read By Group Type Response format:
+	 *    Attribute Opcode: 1 byte
+	 *    Length: 1 byte (size of each group)
+	 *    Group: start | end | <<UUID>>
+	 */
+
+	opdu[0] = ATT_OP_READ_BY_GROUP_RESP;
+	group_start = &opdu[2];
+	group_uuid = &opdu[6];
+
+	for (list = local_attribute_db; list;
+			last = list->data, list = g_list_next(list)) {
+		struct btd_attribute *attr = list->data;
+
+		if (attr->handle < start)
+			continue;
+
+		if (attr->handle > end)
+			break;
+
+		if (bt_uuid_cmp(&attr->type, pattern) != 0)
+			continue;
+
+		if (uuid_type != BT_UUID_UNSPEC &&
+						uuid_type != attr->type.type) {
+			/*
+			 * Groups should contain the same length: UUID16 and
+			 * UUID128 should be sent on different ATT PDUs
+			 */
+			break;
+		}
+
+		/*
+		 * MTU checking should not be shifted up, otherwise the
+		 * handle of last end group will not be set properly.
+		 */
+		if ((plen + group_len) >= ATT_DEFAULT_LE_MTU)
+			break;
+
+		/* Start Grouping handle */
+		att_put_u16(attr->handle, group_start);
+
+		/* Grouping <<UUID>>: Value is little endian */
+		memcpy(group_uuid, attr->value, attr->value_len);
+
+		if (last && group_end) {
+			att_put_u16(last->handle, group_end);
+			group_end += group_len;
+			plen += group_len;
+		}
+
+		/* Grouping initial settings: First grouping */
+		if (uuid_type == BT_UUID_UNSPEC) {
+			uuid_type = attr->type.type;
+
+			/* start(0xXXXX) | end(0xXXXX) | <<UUID>> */
+			group_len = 2 + 2 + bt_uuid_len(&attr->type);
+
+			/* 2: ATT Opcode and Length */
+			plen = 2 + group_len;
+
+			/* Size of each Attribute Data */
+			opdu[1] = group_len;
+
+			group_end = &opdu[4];
+		}
+
+		group_start += group_len;
+		group_uuid += group_len;
+	}
+
+	if (plen == 0) {
+		send_error(attrib, ATT_OP_READ_BY_GROUP_REQ, start,
+						ATT_ECODE_ATTR_NOT_FOUND);
+		return;
+	}
+
+	if (group_end)
+		att_put_u16(last->handle, group_end);
+
+	g_attrib_send(attrib, 0, opdu, plen, NULL, NULL, NULL);
+}
+
+static void read_by_group(GAttrib *attrib, const uint8_t *ipdu, size_t ilen)
+{
+	uint16_t decoded, start, end;
+	bt_uuid_t pattern;
+
+	decoded = dec_read_by_grp_req(ipdu, ilen, &start, &end, &pattern);
+	if (decoded == 0) {
+		send_error(attrib, ipdu[0], 0x0000, ATT_ECODE_INVALID_PDU);
+		return;
+	}
+
+	if (start > end || start == 0x0000) {
+		send_error(attrib, ipdu[0], start, ATT_ECODE_INVALID_HANDLE);
+		return;
+	}
+
+	 /*
+	  * Restricting Read By Group Type to <<Primary>>.
+	  * Removing the checking below requires changes to support
+	  * dynamic values(defined in the upper layer) and additional
+	  * security verification.
+	  */
+	if (bt_uuid_cmp(&pattern, &primary_uuid) != 0) {
+		send_error(attrib, ipdu[0], start, ATT_ECODE_UNSUPP_GRP_TYPE);
+		return;
+	}
+
+	read_by_group_resp(attrib, start, end, &pattern);
+}
+
 static void channel_handler_cb(const uint8_t *ipdu, uint16_t ilen,
 							gpointer user_data)
 {
@@ -133,11 +257,14 @@ static void channel_handler_cb(const uint8_t *ipdu, uint16_t ilen,
 	case ATT_OP_READ_MULTI_REQ:
 	case ATT_OP_PREP_WRITE_REQ:
 	case ATT_OP_EXEC_WRITE_REQ:
-	case ATT_OP_READ_BY_GROUP_REQ:
 	case ATT_OP_SIGNED_WRITE_CMD:
 		send_error(attrib, ipdu[0], 0x0000, ATT_ECODE_REQ_NOT_SUPP);
 		break;
 
+	case ATT_OP_READ_BY_GROUP_REQ:
+		read_by_group(attrib, ipdu, ilen);
+		break;
+
 	/* Responses */
 	case ATT_OP_MTU_RESP:
 	case ATT_OP_FIND_INFO_RESP:
-- 
1.8.3.1


^ permalink raw reply related

* [PATCH BlueZ v1 10/18] gatt: Register ATT command/event handler
From: Claudio Takahasi @ 2014-01-20 18:04 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: claudio.takahasi, Alvaro Silva
In-Reply-To: <1390241103-808-1-git-send-email-claudio.takahasi@openbossa.org>

From: Alvaro Silva <alvaro.silva@openbossa.org>

This patch registers the ATT channel handler to manage incoming ATT
commands and events.
---
 src/gatt.c | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 80 insertions(+)

diff --git a/src/gatt.c b/src/gatt.c
index 4806205..33c3b6a 100644
--- a/src/gatt.c
+++ b/src/gatt.c
@@ -38,6 +38,7 @@
 #include "log.h"
 #include "lib/uuid.h"
 #include "attrib/att.h"
+#include "attrib/gattrib.h"
 
 #include "gatt-dbus.h"
 #include "gatt.h"
@@ -100,12 +101,83 @@ struct btd_attribute *btd_gatt_add_service(const bt_uuid_t *uuid)
 	return attr;
 }
 
+static void send_error(GAttrib *attrib, uint8_t opcode, uint16_t handle,
+								uint8_t ecode)
+{
+	uint8_t pdu[ATT_DEFAULT_LE_MTU];
+	size_t plen;
+
+	plen = enc_error_resp(opcode, handle, ecode, pdu, sizeof(pdu));
+
+	g_attrib_send(attrib, 0, pdu, plen, NULL, NULL, NULL);
+}
+
+static void channel_handler_cb(const uint8_t *ipdu, uint16_t ilen,
+							gpointer user_data)
+{
+	GAttrib *attrib = user_data;
+
+	switch (ipdu[0]) {
+	case ATT_OP_ERROR:
+		break;
+
+	/* Requests */
+	case ATT_OP_WRITE_CMD:
+	case ATT_OP_WRITE_REQ:
+	case ATT_OP_READ_REQ:
+	case ATT_OP_READ_BY_TYPE_REQ:
+	case ATT_OP_MTU_REQ:
+	case ATT_OP_FIND_INFO_REQ:
+	case ATT_OP_FIND_BY_TYPE_REQ:
+	case ATT_OP_READ_BLOB_REQ:
+	case ATT_OP_READ_MULTI_REQ:
+	case ATT_OP_PREP_WRITE_REQ:
+	case ATT_OP_EXEC_WRITE_REQ:
+	case ATT_OP_READ_BY_GROUP_REQ:
+	case ATT_OP_SIGNED_WRITE_CMD:
+		send_error(attrib, ipdu[0], 0x0000, ATT_ECODE_REQ_NOT_SUPP);
+		break;
+
+	/* Responses */
+	case ATT_OP_MTU_RESP:
+	case ATT_OP_FIND_INFO_RESP:
+	case ATT_OP_FIND_BY_TYPE_RESP:
+	case ATT_OP_READ_BY_TYPE_RESP:
+	case ATT_OP_READ_RESP:
+	case ATT_OP_READ_BLOB_RESP:
+	case ATT_OP_READ_MULTI_RESP:
+	case ATT_OP_READ_BY_GROUP_RESP:
+	case ATT_OP_WRITE_RESP:
+	case ATT_OP_PREP_WRITE_RESP:
+	case ATT_OP_EXEC_WRITE_RESP:
+	case ATT_OP_HANDLE_CNF:
+		break;
+
+	/* Notification & Indication */
+	case ATT_OP_HANDLE_NOTIFY:
+	case ATT_OP_HANDLE_IND:
+		break;
+	}
+}
+
+static gboolean unix_hup_cb(GIOChannel *io, GIOCondition cond,
+						gpointer user_data)
+{
+	GAttrib *attrib = user_data;
+
+	g_attrib_unregister_all(attrib);
+	g_attrib_unref(attrib);
+
+	return FALSE;
+}
+
 static gboolean unix_accept_cb(GIOChannel *io, GIOCondition cond,
 							gpointer user_data)
 {
 	struct sockaddr_un uaddr;
 	socklen_t len = sizeof(uaddr);
 	GIOChannel *nio;
+	GAttrib *attrib;
 	int err, nsk, sk;
 
 	sk = g_io_channel_unix_get_fd(io);
@@ -120,6 +192,14 @@ static gboolean unix_accept_cb(GIOChannel *io, GIOCondition cond,
 	nio = g_io_channel_unix_new(nsk);
 	g_io_channel_set_close_on_unref(nio, TRUE);
 	DBG("ATT UNIX socket: %p new client", nio);
+
+	attrib = g_attrib_new(nio);
+
+	g_attrib_register(attrib, GATTRIB_ALL_EVENTS, GATTRIB_ALL_HANDLES,
+					channel_handler_cb, attrib, NULL);
+
+	g_io_add_watch(nio, G_IO_HUP, unix_hup_cb, attrib);
+
 	g_io_channel_unref(nio);
 
 	return TRUE;
-- 
1.8.3.1


^ permalink raw reply related

* [PATCH BlueZ v1 09/18] gattrib: Use default ATT LE MTU for non-standard sockets
From: Claudio Takahasi @ 2014-01-20 18:04 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: claudio.takahasi
In-Reply-To: <1390241103-808-1-git-send-email-claudio.takahasi@openbossa.org>

This patch forces the MTU to 23 (default ATT MTU) if the transport
is not Bluetooth. This is a development purpose change to allow
testing GATT procedures over non-Bluetooth sockets.
---
 attrib/gattrib.c | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/attrib/gattrib.c b/attrib/gattrib.c
index 609b908..fccb2bf 100644
--- a/attrib/gattrib.c
+++ b/attrib/gattrib.c
@@ -468,18 +468,18 @@ GAttrib *g_attrib_new(GIOChannel *io)
 	struct _GAttrib *attrib;
 	uint16_t imtu;
 	uint16_t att_mtu;
-	uint16_t cid;
-	GError *gerr = NULL;
+	uint16_t cid = 0;
 
 	g_io_channel_set_encoding(io, NULL, NULL);
 	g_io_channel_set_buffered(io, FALSE);
 
-	bt_io_get(io, &gerr, BT_IO_OPT_IMTU, &imtu,
-				BT_IO_OPT_CID, &cid, BT_IO_OPT_INVALID);
-	if (gerr) {
-		error("%s", gerr->message);
-		g_error_free(gerr);
-		return NULL;
+	if (bt_io_get(io, NULL, BT_IO_OPT_IMTU, &imtu, BT_IO_OPT_CID, &cid,
+						BT_IO_OPT_INVALID) == FALSE) {
+		/*
+		 * Use default ATT LE MTU for non-standard transports. Used
+		 * for testing purpose only. eg: Unix sockets
+		 */
+		imtu = ATT_DEFAULT_LE_MTU;
 	}
 
 	attrib = g_try_new0(struct _GAttrib, 1);
-- 
1.8.3.1


^ permalink raw reply related

* [PATCH BlueZ v1 08/18] gatt: Add server unix socket
From: Claudio Takahasi @ 2014-01-20 18:04 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: claudio.takahasi
In-Reply-To: <1390241103-808-1-git-send-email-claudio.takahasi@openbossa.org>

This patch adds a server unix socket to handle local ATT traffic. This
is a development purpose feature used to allow local testing without
breaking the current attribute server.
---
 src/gatt.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 67 insertions(+)

diff --git a/src/gatt.c b/src/gatt.c
index ee045b1..4806205 100644
--- a/src/gatt.c
+++ b/src/gatt.c
@@ -25,6 +25,11 @@
 #include <config.h>
 #endif
 
+#include <unistd.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
 #include <glib.h>
 
 #include "adapter.h"
@@ -50,6 +55,7 @@ struct btd_attribute {
 
 static GList *local_attribute_db;
 static uint16_t next_handle = 0x0001;
+static guint unix_watch;
 
 static int local_database_add(uint16_t handle, struct btd_attribute *attr)
 {
@@ -94,11 +100,71 @@ struct btd_attribute *btd_gatt_add_service(const bt_uuid_t *uuid)
 	return attr;
 }
 
+static gboolean unix_accept_cb(GIOChannel *io, GIOCondition cond,
+							gpointer user_data)
+{
+	struct sockaddr_un uaddr;
+	socklen_t len = sizeof(uaddr);
+	GIOChannel *nio;
+	int err, nsk, sk;
+
+	sk = g_io_channel_unix_get_fd(io);
+
+	nsk = accept(sk, (struct sockaddr *) &uaddr, &len);
+	if (nsk < 0) {
+		err = errno;
+		error("ATT UNIX socket accept: %s(%d)", strerror(err), err);
+		return TRUE;
+	}
+
+	nio = g_io_channel_unix_new(nsk);
+	g_io_channel_set_close_on_unref(nio, TRUE);
+	DBG("ATT UNIX socket: %p new client", nio);
+	g_io_channel_unref(nio);
+
+	return TRUE;
+}
+
 void gatt_init(void)
 {
+	struct sockaddr_un uaddr  = {
+		.sun_family     = AF_UNIX,
+		.sun_path       = "\0/bluetooth/unix_att",
+	};
+	GIOChannel *io;
+	int sk, err;
+
 	DBG("Starting GATT server");
 
 	gatt_dbus_manager_register();
+
+	sk = socket(AF_UNIX, SOCK_SEQPACKET | SOCK_NONBLOCK | SOCK_CLOEXEC , 0);
+	if (sk < 0) {
+		err = errno;
+		error("ATT UNIX socket: %s(%d)", strerror(err), err);
+		return;
+	}
+
+	if (bind(sk, (struct sockaddr *) &uaddr, sizeof(uaddr)) < 0) {
+		err = errno;
+		error("binding ATT UNIX socket: %s(%d)", strerror(err), err);
+		close(sk);
+		return;
+	}
+
+	if (listen(sk, 5) < 0) {
+		err = errno;
+		error("listen ATT UNIX socket: %s(%d)", strerror(err), err);
+		close(sk);
+		return;
+	}
+
+	io = g_io_channel_unix_new(sk);
+	g_io_channel_set_close_on_unref(io, TRUE);
+	unix_watch = g_io_add_watch(io,
+				G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
+				unix_accept_cb, NULL);
+	g_io_channel_unref(io);
 }
 
 void gatt_cleanup(void)
@@ -106,4 +172,5 @@ void gatt_cleanup(void)
 	DBG("Stopping GATT server");
 
 	gatt_dbus_manager_unregister();
+	g_source_remove(unix_watch);
 }
-- 
1.8.3.1


^ permalink raw reply related

* [PATCH BlueZ v1 07/18] gatt: Implement UnregisterService
From: Claudio Takahasi @ 2014-01-20 18:04 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: claudio.takahasi, Alvaro Silva
In-Reply-To: <1390241103-808-1-git-send-email-claudio.takahasi@openbossa.org>

From: Alvaro Silva <alvaro.silva@openbossa.org>

This patch implements UnregisterService method of ServiceManager1.
External applications may call this method to unregister a given
service without leaving the system bus.
---
 src/gatt-dbus.c | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/src/gatt-dbus.c b/src/gatt-dbus.c
index fc41d00..1f789b0 100644
--- a/src/gatt-dbus.c
+++ b/src/gatt-dbus.c
@@ -243,6 +243,31 @@ static DBusMessage *register_service(DBusConnection *conn,
 static DBusMessage *unregister_service(DBusConnection *conn,
 					DBusMessage *msg, void *user_data)
 {
+	struct external_app *eapp = user_data;
+	DBusMessageIter iter;
+	const char *path;
+	GSList *list;
+
+	DBG("Unregistering GATT Service");
+
+	if (!dbus_message_iter_init(msg, &iter))
+		return btd_error_invalid_args(msg);
+
+	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_OBJECT_PATH)
+		return btd_error_invalid_args(msg);
+
+	dbus_message_iter_get_basic(&iter, &path);
+
+	list = g_slist_find_custom(external_apps, path, external_app_path_cmp);
+	if (list == NULL)
+		return btd_error_does_not_exist(msg);
+
+	eapp = list->data;
+	if (g_strcmp0(dbus_message_get_sender(msg), eapp->owner) != 0)
+		return btd_error_does_not_exist(msg);
+
+	g_dbus_remove_watch(conn, eapp->watch);
+
 	return dbus_message_new_method_return(msg);
 }
 
-- 
1.8.3.1


^ permalink raw reply related

* [PATCH BlueZ v1 06/18] gatt: Add external services tracking
From: Claudio Takahasi @ 2014-01-20 18:04 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: claudio.takahasi, Alvaro Silva
In-Reply-To: <1390241103-808-1-git-send-email-claudio.takahasi@openbossa.org>

From: Alvaro Silva <alvaro.silva@openbossa.org>

All primary services declarations provided by an external application
will be automatically inserted in the attribute database.
---
 src/gatt-dbus.c | 109 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 109 insertions(+)

diff --git a/src/gatt-dbus.c b/src/gatt-dbus.c
index fc41b78..fc41d00 100644
--- a/src/gatt-dbus.c
+++ b/src/gatt-dbus.c
@@ -39,15 +39,21 @@
 #include "log.h"
 
 #include "error.h"
+#include "gatt.h"
 #include "gatt-dbus.h"
 
+#define SERVICE_IFACE				"org.bluez.Service1"
 #define SERVICE_MGR_IFACE			"org.bluez.ServiceManager1"
 
+#define REGISTER_TIMER         1
+
 struct external_app {
 	char *owner;
 	char *path;
 	GDBusClient *client;
+	GSList *proxies;
 	unsigned int watch;
+	guint register_timer;
 };
 
 static GSList *external_apps;
@@ -60,6 +66,36 @@ static int external_app_path_cmp(gconstpointer a, gconstpointer b)
 	return g_strcmp0(eapp->path, path);
 }
 
+static void proxy_added(GDBusProxy *proxy, void *user_data)
+{
+	struct external_app *eapp = user_data;
+	const char *interface, *path;
+
+	interface = g_dbus_proxy_get_interface(proxy);
+	path = g_dbus_proxy_get_path(proxy);
+
+	DBG("path %s iface %s", path, interface);
+
+	if (g_strcmp0(interface, SERVICE_IFACE) != 0)
+		return;
+
+	eapp->proxies = g_slist_append(eapp->proxies, proxy);
+}
+
+static void proxy_removed(GDBusProxy *proxy, void *user_data)
+{
+	struct external_app *eapp = user_data;
+	const char *interface, *path;
+
+	interface = g_dbus_proxy_get_interface(proxy);
+	path = g_dbus_proxy_get_path(proxy);
+
+	DBG("path %s iface %s", path, interface);
+
+	eapp->proxies = g_slist_remove(eapp->proxies, proxy);
+}
+
+
 static void external_app_watch_destroy(gpointer user_data)
 {
 	struct external_app *eapp = user_data;
@@ -70,6 +106,9 @@ static void external_app_watch_destroy(gpointer user_data)
 
 	g_dbus_client_unref(eapp->client);
 
+	if (eapp->register_timer)
+		g_source_remove(eapp->register_timer);
+
 	g_free(eapp->owner);
 	g_free(eapp->path);
 	g_free(eapp);
@@ -99,9 +138,75 @@ static struct external_app *new_external_app(DBusConnection *conn,
 	eapp->client = client;
 	eapp->path = g_strdup(path);
 
+	g_dbus_client_set_proxy_handlers(client, proxy_added, proxy_removed,
+								NULL, eapp);
+
 	return eapp;
 }
 
+static int register_external_service(GDBusProxy *proxy)
+{
+	DBusMessageIter iter;
+	const char *uuid;
+	bt_uuid_t btuuid;
+
+	if (!g_dbus_proxy_get_property(proxy, "UUID", &iter))
+		return -EINVAL;
+
+	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
+		return -EINVAL;
+
+	dbus_message_iter_get_basic(&iter, &uuid);
+
+	if (bt_string_to_uuid(&btuuid, uuid) < 0)
+		return -EINVAL;
+
+	if (btd_gatt_add_service(&btuuid) == NULL)
+		return -EINVAL;
+
+	return 0;
+}
+
+static gboolean finish_register(gpointer user_data)
+{
+	struct external_app *eapp = user_data;
+	GSList *list;
+
+	/*
+	 * It is not possible to detect when the last proxy object
+	 * was reported. "Proxy added" handler reports objects
+	 * added on demand or returned by GetManagedObjects().
+	 * This timer helps to register all the GATT declarations
+	 * (services, characteristics and descriptors) after fetching
+	 * all the D-Bus objects.
+	 */
+
+	eapp->register_timer = 0;
+
+	for (list = eapp->proxies; list; list = g_slist_next(list)) {
+		const char *interface, *path;
+		GDBusProxy *proxy = list->data;
+
+		interface = g_dbus_proxy_get_interface(proxy);
+		path = g_dbus_proxy_get_path(proxy);
+
+		if (g_strcmp0(SERVICE_IFACE, interface) != 0)
+			continue;
+
+		if (g_strcmp0(path, eapp->path) != 0)
+			continue;
+
+		if (register_external_service(proxy) < 0) {
+			DBG("Inconsistent external service: %s", path);
+			continue;
+		}
+
+		DBG("External service: %s", path);
+	}
+
+	return FALSE;
+}
+
 static DBusMessage *register_service(DBusConnection *conn,
 					DBusMessage *msg, void *user_data)
 {
@@ -109,6 +214,8 @@ static DBusMessage *register_service(DBusConnection *conn,
 	DBusMessageIter iter;
 	const char *path;
 
+	DBG("Registering GATT Service");
+
 	if (!dbus_message_iter_init(msg, &iter))
 		return btd_error_invalid_args(msg);
 
@@ -127,6 +234,8 @@ static DBusMessage *register_service(DBusConnection *conn,
 	external_apps = g_slist_prepend(external_apps, eapp);
 
 	DBG("New app %p: %s", eapp, path);
+	eapp->register_timer = g_timeout_add_seconds(REGISTER_TIMER,
+							finish_register, eapp);
 
 	return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
 }
-- 
1.8.3.1


^ permalink raw reply related

* [PATCH BlueZ v1 05/18] gatt: Add helper for creating GATT services
From: Claudio Takahasi @ 2014-01-20 18:04 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: claudio.takahasi, Andre Guedes
In-Reply-To: <1390241103-808-1-git-send-email-claudio.takahasi@openbossa.org>

From: Andre Guedes <andre.guedes@openbossa.org>

This patch adds the btd_gatt_add_service() helper which adds a
GATT Service declaration to the local attribute database.
---
 lib/uuid.h |  5 +++++
 src/gatt.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/gatt.h | 10 ++++++++++
 3 files changed, 77 insertions(+)

diff --git a/lib/uuid.h b/lib/uuid.h
index c24cee5..237145b 100644
--- a/lib/uuid.h
+++ b/lib/uuid.h
@@ -158,6 +158,11 @@ void bt_uuid_to_uuid128(const bt_uuid_t *src, bt_uuid_t *dst);
 int bt_uuid_to_string(const bt_uuid_t *uuid, char *str, size_t n);
 int bt_string_to_uuid(bt_uuid_t *uuid, const char *string);
 
+static inline int bt_uuid_len(const bt_uuid_t *uuid)
+{
+	return uuid->type / 8;
+}
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/src/gatt.c b/src/gatt.c
index e8b691a..ee045b1 100644
--- a/src/gatt.c
+++ b/src/gatt.c
@@ -27,11 +27,73 @@
 
 #include <glib.h>
 
+#include "adapter.h"
+#include "device.h"
+
 #include "log.h"
+#include "lib/uuid.h"
+#include "attrib/att.h"
 
 #include "gatt-dbus.h"
 #include "gatt.h"
 
+/* Common GATT UUIDs */
+static const bt_uuid_t primary_uuid  = { .type = BT_UUID16,
+					.value.u16 = GATT_PRIM_SVC_UUID };
+
+struct btd_attribute {
+	uint16_t handle;
+	bt_uuid_t type;
+	uint16_t value_len;
+	uint8_t value[0];
+};
+
+static GList *local_attribute_db;
+static uint16_t next_handle = 0x0001;
+
+static int local_database_add(uint16_t handle, struct btd_attribute *attr)
+{
+	attr->handle = handle;
+
+	local_attribute_db = g_list_append(local_attribute_db, attr);
+
+	return 0;
+}
+
+struct btd_attribute *btd_gatt_add_service(const bt_uuid_t *uuid)
+{
+	uint16_t len = bt_uuid_len(uuid);
+	struct btd_attribute *attr = g_malloc0(sizeof(struct btd_attribute) +
+									len);
+
+	/*
+	 * Service DECLARATION
+	 *
+	 *   TYPE         ATTRIBUTE VALUE
+	 * +-------+---------------------------------+
+	 * |0x2800 | 0xYYYY...                       |
+	 * | (1)   | (2)                             |
+	 * +------+----------------------------------+
+	 * (1) - 2 octets: Primary/Secondary Service UUID
+	 * (2) - 2 or 16 octets: Service UUID
+	 */
+
+	attr->type = primary_uuid;
+
+	att_put_uuid(*uuid, attr->value);
+	attr->value_len = len;
+
+	if (local_database_add(next_handle, attr) < 0) {
+		g_free(attr);
+		return NULL;
+	}
+
+	/* TODO: missing overflow checking */
+	next_handle = next_handle + 1;
+
+	return attr;
+}
+
 void gatt_init(void)
 {
 	DBG("Starting GATT server");
diff --git a/src/gatt.h b/src/gatt.h
index 3a320b4..8dd1312 100644
--- a/src/gatt.h
+++ b/src/gatt.h
@@ -21,6 +21,16 @@
  *
  */
 
+struct btd_attribute;
+
 void gatt_init(void);
 
 void gatt_cleanup(void);
+
+/* btd_gatt_add_service - Add a service declaration to local attribute database.
+ * @uuid:	Service UUID.
+ *
+ * Returns a reference to service declaration attribute. In case of error,
+ * NULL is returned.
+ */
+struct btd_attribute *btd_gatt_add_service(const bt_uuid_t *uuid);
-- 
1.8.3.1


^ permalink raw reply related

* [PATCH BlueZ v1 04/18] lib: Move GATT UUID to uuid.h
From: Claudio Takahasi @ 2014-01-20 18:04 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: claudio.takahasi
In-Reply-To: <1390241103-808-1-git-send-email-claudio.takahasi@openbossa.org>

This patch moves GATT UUIDs definitions to a common header. uuid.h contains
helper functions to manipulate Bluetooth UUIDs and some common BR/EDR services
UUIDs.
---
 attrib/gatt.h | 25 -------------------------
 lib/uuid.h    | 25 +++++++++++++++++++++++++
 2 files changed, 25 insertions(+), 25 deletions(-)

diff --git a/attrib/gatt.h b/attrib/gatt.h
index 0f113e7..4fea3eb 100644
--- a/attrib/gatt.h
+++ b/attrib/gatt.h
@@ -24,31 +24,6 @@
 
 #include <bluetooth/sdp.h>
 
-/* GATT Profile Attribute types */
-#define GATT_PRIM_SVC_UUID		0x2800
-#define GATT_SND_SVC_UUID		0x2801
-#define GATT_INCLUDE_UUID		0x2802
-#define GATT_CHARAC_UUID		0x2803
-
-/* GATT Characteristic Types */
-#define GATT_CHARAC_DEVICE_NAME			0x2A00
-#define GATT_CHARAC_APPEARANCE			0x2A01
-#define GATT_CHARAC_PERIPHERAL_PRIV_FLAG	0x2A02
-#define GATT_CHARAC_RECONNECTION_ADDRESS	0x2A03
-#define GATT_CHARAC_PERIPHERAL_PREF_CONN	0x2A04
-#define GATT_CHARAC_SERVICE_CHANGED		0x2A05
-
-/* GATT Characteristic Descriptors */
-#define GATT_CHARAC_EXT_PROPER_UUID	0x2900
-#define GATT_CHARAC_USER_DESC_UUID	0x2901
-#define GATT_CLIENT_CHARAC_CFG_UUID	0x2902
-#define GATT_SERVER_CHARAC_CFG_UUID	0x2903
-#define GATT_CHARAC_FMT_UUID		0x2904
-#define GATT_CHARAC_AGREG_FMT_UUID	0x2905
-#define GATT_CHARAC_VALID_RANGE_UUID	0x2906
-#define GATT_EXTERNAL_REPORT_REFERENCE	0x2907
-#define GATT_REPORT_REFERENCE		0x2908
-
 /* Client Characteristic Configuration bit field */
 #define GATT_CLIENT_CHARAC_CFG_NOTIF_BIT	0x0001
 #define GATT_CLIENT_CHARAC_CFG_IND_BIT		0x0002
diff --git a/lib/uuid.h b/lib/uuid.h
index 95e5a9a..c24cee5 100644
--- a/lib/uuid.h
+++ b/lib/uuid.h
@@ -105,6 +105,31 @@ extern "C" {
 #define OBEX_MNS_UUID		"00001133-0000-1000-8000-00805f9b34fb"
 #define OBEX_MAP_UUID		"00001134-0000-1000-8000-00805f9b34fb"
 
+/* GATT UUIDs section */
+#define GATT_PRIM_SVC_UUID				0x2800
+#define GATT_SND_SVC_UUID				0x2801
+#define GATT_INCLUDE_UUID				0x2802
+#define GATT_CHARAC_UUID				0x2803
+
+/* GATT Characteristic Types */
+#define GATT_CHARAC_DEVICE_NAME				0x2A00
+#define GATT_CHARAC_APPEARANCE				0x2A01
+#define GATT_CHARAC_PERIPHERAL_PRIV_FLAG		0x2A02
+#define GATT_CHARAC_RECONNECTION_ADDRESS		0x2A03
+#define GATT_CHARAC_PERIPHERAL_PREF_CONN		0x2A04
+#define GATT_CHARAC_SERVICE_CHANGED			0x2A05
+
+/* GATT Characteristic Descriptors */
+#define GATT_CHARAC_EXT_PROPER_UUID			0x2900
+#define GATT_CHARAC_USER_DESC_UUID			0x2901
+#define GATT_CLIENT_CHARAC_CFG_UUID			0x2902
+#define GATT_SERVER_CHARAC_CFG_UUID			0x2903
+#define GATT_CHARAC_FMT_UUID				0x2904
+#define GATT_CHARAC_AGREG_FMT_UUID			0x2905
+#define GATT_CHARAC_VALID_RANGE_UUID			0x2906
+#define GATT_EXTERNAL_REPORT_REFERENCE			0x2907
+#define GATT_REPORT_REFERENCE				0x2908
+
 typedef struct {
 	enum {
 		BT_UUID_UNSPEC = 0,
-- 
1.8.3.1


^ permalink raw reply related

* [PATCH BlueZ v1 03/18] gatt: Add registering external service
From: Claudio Takahasi @ 2014-01-20 18:04 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: claudio.takahasi, Alvaro Silva
In-Reply-To: <1390241103-808-1-git-send-email-claudio.takahasi@openbossa.org>

From: Alvaro Silva <alvaro.silva@openbossa.org>

This patch allows external applications register a given service on
Bluez. Applications must provide an object path and a dictionary of
options. Options dictionary will be used later to provide additional
service information.
---
 src/gatt-dbus.c | 89 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 88 insertions(+), 1 deletion(-)

diff --git a/src/gatt-dbus.c b/src/gatt-dbus.c
index 90a321b..fc41b78 100644
--- a/src/gatt-dbus.c
+++ b/src/gatt-dbus.c
@@ -26,22 +26,109 @@
 #endif
 
 #include <stdint.h>
+#include <errno.h>
 
 #include <glib.h>
 #include <dbus/dbus.h>
 #include <gdbus/gdbus.h>
 
+#include "adapter.h"
+#include "device.h"
+#include "lib/uuid.h"
 #include "dbus-common.h"
 #include "log.h"
 
+#include "error.h"
 #include "gatt-dbus.h"
 
 #define SERVICE_MGR_IFACE			"org.bluez.ServiceManager1"
 
+struct external_app {
+	char *owner;
+	char *path;
+	GDBusClient *client;
+	unsigned int watch;
+};
+
+static GSList *external_apps;
+
+static int external_app_path_cmp(gconstpointer a, gconstpointer b)
+{
+	const struct external_app *eapp = a;
+	const char *path = b;
+
+	return g_strcmp0(eapp->path, path);
+}
+
+static void external_app_watch_destroy(gpointer user_data)
+{
+	struct external_app *eapp = user_data;
+
+	/* TODO: Remove from the database */
+
+	external_apps = g_slist_remove(external_apps, eapp);
+
+	g_dbus_client_unref(eapp->client);
+
+	g_free(eapp->owner);
+	g_free(eapp->path);
+	g_free(eapp);
+}
+
+static struct external_app *new_external_app(DBusConnection *conn,
+					const char *sender, const char *path)
+{
+	struct external_app *eapp;
+	GDBusClient *client;
+
+	client = g_dbus_client_new(conn, sender, "/");
+	if (client == NULL)
+		return NULL;
+
+	eapp = g_new0(struct external_app, 1);
+
+	eapp->watch = g_dbus_add_disconnect_watch(btd_get_dbus_connection(),
+			sender, NULL, eapp, external_app_watch_destroy);
+	if (eapp->watch == 0) {
+		g_dbus_client_unref(client);
+		g_free(eapp);
+		return NULL;
+	}
+
+	eapp->owner = g_strdup(sender);
+	eapp->client = client;
+	eapp->path = g_strdup(path);
+
+	return eapp;
+}
+
 static DBusMessage *register_service(DBusConnection *conn,
 					DBusMessage *msg, void *user_data)
 {
-	return dbus_message_new_method_return(msg);
+	struct external_app *eapp;
+	DBusMessageIter iter;
+	const char *path;
+
+	if (!dbus_message_iter_init(msg, &iter))
+		return btd_error_invalid_args(msg);
+
+	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_OBJECT_PATH)
+		return btd_error_invalid_args(msg);
+
+	dbus_message_iter_get_basic(&iter, &path);
+
+	if (g_slist_find_custom(external_apps, path, external_app_path_cmp))
+		return btd_error_already_exists(msg);
+
+	eapp = new_external_app(conn, dbus_message_get_sender(msg), path);
+	if (eapp == NULL)
+		return btd_error_failed(msg, "Not enough resources");
+
+	external_apps = g_slist_prepend(external_apps, eapp);
+
+	DBG("New app %p: %s", eapp, path);
+
+	return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
 }
 
 static DBusMessage *unregister_service(DBusConnection *conn,
-- 
1.8.3.1


^ permalink raw reply related

* [PATCH BlueZ v1 02/18] gatt: Register Manager D-Bus Interface
From: Claudio Takahasi @ 2014-01-20 18:04 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: claudio.takahasi, Alvaro Silva
In-Reply-To: <1390241103-808-1-git-send-email-claudio.takahasi@openbossa.org>

From: Alvaro Silva <alvaro.silva@openbossa.org>

This patch registers the Service Manager D-Bus Interface. This
interface implements the methods to allow external application register
and unregister GATT Services.
---
 Makefile.am     |  1 +
 src/gatt-dbus.c | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/gatt-dbus.h | 25 +++++++++++++++++++
 src/gatt.c      |  9 +++++++
 4 files changed, 110 insertions(+)
 create mode 100644 src/gatt-dbus.c
 create mode 100644 src/gatt-dbus.h

diff --git a/Makefile.am b/Makefile.am
index 1444f0e..c395874 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -146,6 +146,7 @@ src_bluetoothd_SOURCES = $(builtin_sources) \
 			src/adapter.h src/adapter.c \
 			src/profile.h src/profile.c \
 			src/service.h src/service.c \
+			src/gatt-dbus.h src/gatt-dbus.c \
 			src/gatt.h src/gatt.c \
 			src/device.h src/device.c src/attio.h \
 			src/dbus-common.c src/dbus-common.h \
diff --git a/src/gatt-dbus.c b/src/gatt-dbus.c
new file mode 100644
index 0000000..90a321b
--- /dev/null
+++ b/src/gatt-dbus.c
@@ -0,0 +1,75 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2014  Instituto Nokia de Tecnologia - INdT
+ *
+ *
+ *  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 <stdint.h>
+
+#include <glib.h>
+#include <dbus/dbus.h>
+#include <gdbus/gdbus.h>
+
+#include "dbus-common.h"
+#include "log.h"
+
+#include "gatt-dbus.h"
+
+#define SERVICE_MGR_IFACE			"org.bluez.ServiceManager1"
+
+static DBusMessage *register_service(DBusConnection *conn,
+					DBusMessage *msg, void *user_data)
+{
+	return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *unregister_service(DBusConnection *conn,
+					DBusMessage *msg, void *user_data)
+{
+	return dbus_message_new_method_return(msg);
+}
+
+static const GDBusMethodTable methods[] = {
+	{ GDBUS_EXPERIMENTAL_METHOD("RegisterService",
+				GDBUS_ARGS({ "service", "o"},
+						{ "options", "a{sv}"}),
+				NULL, register_service) },
+	{ GDBUS_EXPERIMENTAL_METHOD("UnregisterService",
+				GDBUS_ARGS({"service", "o"}),
+				NULL, unregister_service) },
+	{ }
+};
+
+gboolean gatt_dbus_manager_register(void)
+{
+	return g_dbus_register_interface(btd_get_dbus_connection(),
+					"/org/bluez", SERVICE_MGR_IFACE,
+					methods, NULL, NULL, NULL, NULL);
+}
+
+void gatt_dbus_manager_unregister(void)
+{
+	g_dbus_unregister_interface(btd_get_dbus_connection(), "/org/bluez",
+							SERVICE_MGR_IFACE);
+}
diff --git a/src/gatt-dbus.h b/src/gatt-dbus.h
new file mode 100644
index 0000000..310cfa9
--- /dev/null
+++ b/src/gatt-dbus.h
@@ -0,0 +1,25 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2014  Instituto Nokia de Tecnologia - INdT
+ *
+ *
+ *  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
+ *
+ */
+
+gboolean gatt_dbus_manager_register(void);
+void gatt_dbus_manager_unregister(void);
diff --git a/src/gatt.c b/src/gatt.c
index 06619f0..e8b691a 100644
--- a/src/gatt.c
+++ b/src/gatt.c
@@ -25,14 +25,23 @@
 #include <config.h>
 #endif
 
+#include <glib.h>
+
+#include "log.h"
+
+#include "gatt-dbus.h"
 #include "gatt.h"
 
 void gatt_init(void)
 {
+	DBG("Starting GATT server");
 
+	gatt_dbus_manager_register();
 }
 
 void gatt_cleanup(void)
 {
+	DBG("Stopping GATT server");
 
+	gatt_dbus_manager_unregister();
 }
-- 
1.8.3.1


^ 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