Linux bluetooth development
 help / color / mirror / Atom feed
* Re: [PATCH 7/7] Bluetooth: Fix not returning proper error in RFCOMM
From: Gustavo F. Padovan @ 2010-11-05 14:26 UTC (permalink / raw)
  To: Ville Tervo; +Cc: linux-bluetooth@vger.kernel.org
In-Reply-To: <20101105140158.GE19903@null>

Hi Ville,

* Ville Tervo <ville.tervo@nokia.com> [2010-11-05 16:01:58 +0200]:

> Hi Gustavo,
> 
> On Tue, Nov 02, 2010 at 04:03:18PM +0100, ext Gustavo F. Padovan wrote:
> > Return 0 in that situation could lead to errors in the caller.
> > 
> > Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
> > ---
> >  net/bluetooth/rfcomm/sock.c |    2 +-
> >  1 files changed, 1 insertions(+), 1 deletions(-)
> > 
> > diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c
> > index e48fbca..cd7e27a 100644
> > --- a/net/bluetooth/rfcomm/sock.c
> > +++ b/net/bluetooth/rfcomm/sock.c
> > @@ -930,7 +930,7 @@ int rfcomm_connect_ind(struct rfcomm_session *s, u8 channel, struct rfcomm_dlc *
> >  	/* Check if we have socket listening on channel */
> >  	parent = rfcomm_get_sock_by_channel(BT_LISTEN, channel, &src);
> >  	if (!parent)
> > -		return 0;
> > +		return -EINVAL;
> 
> Did you check rfcomm/core.c?
> 
> I think this change breaks the logic in there. IOW continues connection
> establisment instead of tearing down the link.

I understood that part of the code wrong, I'm going to drop this patch.
Thanks fo looking into this.

-- 
Gustavo F. Padovan
ProFUSION embedded systems - http://profusion.mobi

^ permalink raw reply

* Re: [PATCH 7/7] Bluetooth: Fix not returning proper error in RFCOMM
From: Ville Tervo @ 2010-11-05 14:01 UTC (permalink / raw)
  To: ext Gustavo F. Padovan; +Cc: linux-bluetooth@vger.kernel.org
In-Reply-To: <1288710198-6108-7-git-send-email-padovan@profusion.mobi>

Hi Gustavo,

On Tue, Nov 02, 2010 at 04:03:18PM +0100, ext Gustavo F. Padovan wrote:
> Return 0 in that situation could lead to errors in the caller.
> 
> Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
> ---
>  net/bluetooth/rfcomm/sock.c |    2 +-
>  1 files changed, 1 insertions(+), 1 deletions(-)
> 
> diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c
> index e48fbca..cd7e27a 100644
> --- a/net/bluetooth/rfcomm/sock.c
> +++ b/net/bluetooth/rfcomm/sock.c
> @@ -930,7 +930,7 @@ int rfcomm_connect_ind(struct rfcomm_session *s, u8 channel, struct rfcomm_dlc *
>  	/* Check if we have socket listening on channel */
>  	parent = rfcomm_get_sock_by_channel(BT_LISTEN, channel, &src);
>  	if (!parent)
> -		return 0;
> +		return -EINVAL;

Did you check rfcomm/core.c?

I think this change breaks the logic in there. IOW continues connection
establisment instead of tearing down the link.

-- 
Ville

^ permalink raw reply

* Re: [PATCH 1/7] Bluetooth: Hold the lock inside l2cap_get_sock_by_addr()
From: Ville Tervo @ 2010-11-05 13:49 UTC (permalink / raw)
  To: ext Gustavo F. Padovan; +Cc: linux-bluetooth@vger.kernel.org
In-Reply-To: <1288710198-6108-1-git-send-email-padovan@profusion.mobi>

Hi Gustavo,

On Tue, Nov 02, 2010 at 04:03:12PM +0100, ext Gustavo F. Padovan wrote:
> It also have to change the name of the function to
> l2cap_get_sock_by_addr() because we do hold the lock inside it now.
> 
> Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
> ---
>  net/bluetooth/l2cap.c |   17 ++++++-----------
>  1 files changed, 6 insertions(+), 11 deletions(-)
> 
> diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c
> index 6f931cc..3d48867 100644
> --- a/net/bluetooth/l2cap.c
> +++ b/net/bluetooth/l2cap.c
> @@ -728,15 +728,18 @@ static inline void l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, stru
>  }
>  
>  /* ---- Socket interface ---- */
> -static struct sock *__l2cap_get_sock_by_addr(__le16 psm, bdaddr_t *src)
> +static struct sock *l2cap_get_sock_by_addr(__le16 psm, bdaddr_t *src)
>  {
>  	struct sock *sk;
>  	struct hlist_node *node;
> +
> +	write_lock_bh(&l2cap_sk_list.lock);

Code is only reading so read_lock_bh would be enough?

>
>  	sk_for_each(sk, node, &l2cap_sk_list.head)
>  		if (l2cap_pi(sk)->sport == psm && !bacmp(&bt_sk(sk)->src, src))
>  			goto found;
>  	sk = NULL;
>  found:
> +	write_unlock_bh(&l2cap_sk_list.lock);
>  	return sk;
>  }
>  
> @@ -1024,9 +1027,7 @@ static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen)
>  		}
>  	}
>  
> -	write_lock_bh(&l2cap_sk_list.lock);
> -
> -	if (la.l2_psm && __l2cap_get_sock_by_addr(la.l2_psm, &la.l2_bdaddr)) {
> +	if (la.l2_psm && l2cap_get_sock_by_addr(la.l2_psm, &la.l2_bdaddr)) {
>  		err = -EADDRINUSE;
>  	} else {
>  		/* Save source address */
> @@ -1040,8 +1041,6 @@ static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen)
>  			l2cap_pi(sk)->sec_level = BT_SECURITY_SDP;
>  	}
>  
> -	write_unlock_bh(&l2cap_sk_list.lock);
> -
>  done:
>  	release_sock(sk);
>  	return err;
> @@ -1257,18 +1256,14 @@ static int l2cap_sock_listen(struct socket *sock, int backlog)
>  
>  		err = -EINVAL;
>  
> -		write_lock_bh(&l2cap_sk_list.lock);
> -
>  		for (psm = 0x1001; psm < 0x1100; psm += 2)
> -			if (!__l2cap_get_sock_by_addr(cpu_to_le16(psm), src)) {
> +			if (!l2cap_get_sock_by_addr(cpu_to_le16(psm), src)) {
>  				l2cap_pi(sk)->psm   = cpu_to_le16(psm);
>  				l2cap_pi(sk)->sport = cpu_to_le16(psm);
>  				err = 0;
>  				break;
>  			}
>  
> -		write_unlock_bh(&l2cap_sk_list.lock);
> -
>  		if (err < 0)
>  			goto done;
>  	}
> -- 
> 1.7.3.1
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* RE: [PATCH 2/4] Sim Access Profile Manager
From: Waldemar.Rymarkiewicz @ 2010-11-05 13:31 UTC (permalink / raw)
  To: johan.hedberg; +Cc: linux-bluetooth, suraj, joakim.xj.ceder
In-Reply-To: <20101105093032.GA32149@jh-x301>

[-- Attachment #1: Type: text/plain, Size: 299 bytes --]

Hi Johan 

>
>> +++ b/sap/server.h
>> @@ -0,0 +1,25 @@
>> +/*
>> + *  BlueZ - Bluetooth protocol stack for Linux
>> + *
>> + *  Copyright (C) 2010 Claudio 
>> +Takahasi<claudio.takahasi@openbossa.org>
>
>Same here.
>

Thanks for comments. I updated the patch. 

Regards,
/Waldek


[-- Attachment #2: 0002-Sim-Access-Profile-Manager.patch --]
[-- Type: application/octet-stream, Size: 10127 bytes --]

From 2896b2af5da20c69823c6df602f3594125e92aae Mon Sep 17 00:00:00 2001
From: Waldemar Rymarkiewicz <waldemar.rymarkiewicz@tieto.com>
Date: Wed, 20 Oct 2010 11:59:43 +0200
Subject: [PATCH 2/4] Sim Access Profile Manager

Add a SAP plugin main file and the plugin manager. Also include the SAP
plugin in the Makefile.
---
 Makefile.am   |    7 ++++
 acinclude.m4  |    6 ++++
 sap/main.c    |   55 +++++++++++++++++++++++++++++++++
 sap/manager.c |   93 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 sap/manager.h |   22 +++++++++++++
 sap/server.c  |   48 +++++++++++++++++++++++++++++
 sap/server.h  |   26 ++++++++++++++++
 7 files changed, 257 insertions(+), 0 deletions(-)
 create mode 100644 sap/main.c
 create mode 100644 sap/manager.c
 create mode 100644 sap/manager.h
 create mode 100644 sap/server.c
 create mode 100644 sap/server.h

diff --git a/Makefile.am b/Makefile.am
index e1183de..c767b4c 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -142,6 +142,13 @@ audio_libtelephony_a_SOURCES = audio/telephony.h audio/telephony-dummy.c \
 				audio/telephony-maemo6.c
 endif
 
+if SAPPLUGIN
+builtin_modules += sap
+builtin_sources += sap/main.c \
+			sap/manager.h sap/manager.c \
+			sap/server.h sap/server.c
+endif
+
 if INPUTPLUGIN
 builtin_modules += input
 builtin_sources += input/main.c \
diff --git a/acinclude.m4 b/acinclude.m4
index 287f07d..1f76b4d 100644
--- a/acinclude.m4
+++ b/acinclude.m4
@@ -174,6 +174,7 @@ AC_DEFUN([AC_ARG_BLUEZ], [
 	input_enable=yes
 	serial_enable=yes
 	network_enable=yes
+	sap_enable=yes
 	service_enable=yes
 	health_enable=no
 	pnat_enable=no
@@ -210,6 +211,10 @@ AC_DEFUN([AC_ARG_BLUEZ], [
 		network_enable=${enableval}
 	])
 
+	AC_ARG_ENABLE(sap, AC_HELP_STRING([--disable-sap], [disable sap plugin]), [
+		sap_enable=${enableval}
+	])
+
 	AC_ARG_ENABLE(serial, AC_HELP_STRING([--disable-serial], [disable serial plugin]), [
 		serial_enable=${enableval}
 	])
@@ -351,6 +356,7 @@ AC_DEFUN([AC_ARG_BLUEZ], [
 	AM_CONDITIONAL(INPUTPLUGIN, test "${input_enable}" = "yes")
 	AM_CONDITIONAL(SERIALPLUGIN, test "${serial_enable}" = "yes")
 	AM_CONDITIONAL(NETWORKPLUGIN, test "${network_enable}" = "yes")
+	AM_CONDITIONAL(SAPPLUGIN, test "${sap_enable}" = "yes")
 	AM_CONDITIONAL(SERVICEPLUGIN, test "${service_enable}" = "yes")
 	AM_CONDITIONAL(HEALTHPLUGIN, test "${health_enable}" = "yes")
 	AM_CONDITIONAL(MCAP, test "${health_enable}" = "yes")
diff --git a/sap/main.c b/sap/main.c
new file mode 100644
index 0000000..c9c90bd
--- /dev/null
+++ b/sap/main.c
@@ -0,0 +1,55 @@
+/*
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2010 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 <gdbus.h>
+#include "plugin.h"
+#include "manager.h"
+
+static DBusConnection *connection;
+
+static int sap_init(void)
+{
+	connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
+
+	if (!connection)
+		return -EIO;
+
+	if (sap_manager_init(connection) < 0) {
+		dbus_connection_unref(connection);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static void sap_exit(void)
+{
+	sap_manager_exit();
+
+	dbus_connection_unref(connection);
+}
+
+BLUETOOTH_PLUGIN_DEFINE(sap, VERSION,
+		BLUETOOTH_PLUGIN_PRIORITY_DEFAULT, sap_init, sap_exit)
diff --git a/sap/manager.c b/sap/manager.c
new file mode 100644
index 0000000..a97f434
--- /dev/null
+++ b/sap/manager.c
@@ -0,0 +1,93 @@
+/*
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2010 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 <bluetooth/bluetooth.h>
+#include <bluetooth/hci.h>
+#include <bluetooth/sdp.h>
+#include <bluetooth/sdp_lib.h>
+
+#include <gdbus.h>
+
+#include "log.h"
+#include "adapter.h"
+#include "device.h"
+
+#include "manager.h"
+#include "server.h"
+
+static DBusConnection *connection = NULL;
+
+static int sap_server_probe(struct btd_adapter *adapter)
+{
+	const char *path = adapter_get_path(adapter);
+	bdaddr_t src;
+
+	DBG("path %s", path);
+
+	adapter_get_address(adapter, &src);
+
+	return sap_server_register(path, &src);
+}
+
+static void sap_server_remove(struct btd_adapter *adapter)
+{
+	const char *path = adapter_get_path(adapter);
+
+	DBG("path %s", path);
+
+	sap_server_unregister(path);
+}
+
+static struct btd_adapter_driver sap_server_driver = {
+	.name	= "sap-server",
+	.probe	= sap_server_probe,
+	.remove	= sap_server_remove,
+};
+
+int sap_manager_init(DBusConnection *conn)
+{
+	connection = dbus_connection_ref(conn);
+
+	if (sap_server_init(connection) < 0) {
+		error("Can't init SAP server");
+		dbus_connection_unref(conn);
+		return -1;
+	}
+
+	btd_register_adapter_driver(&sap_server_driver);
+
+	return 0;
+}
+
+void sap_manager_exit(void)
+{
+	btd_unregister_adapter_driver(&sap_server_driver);
+
+	dbus_connection_unref(connection);
+	connection = NULL;
+
+	sap_server_exit();
+}
diff --git a/sap/manager.h b/sap/manager.h
new file mode 100644
index 0000000..e08c882
--- /dev/null
+++ b/sap/manager.h
@@ -0,0 +1,22 @@
+/*
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2010 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
+ */
+
+int sap_manager_init(DBusConnection *conn);
+void sap_manager_exit(void);
diff --git a/sap/server.c b/sap/server.c
new file mode 100644
index 0000000..2728778
--- /dev/null
+++ b/sap/server.c
@@ -0,0 +1,48 @@
+/*
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2010 ST-Ericsson SA
+ *
+ *  Author: Waldemar Rymarkiewicz <waldemar.rymarkiewicz@tieto.com> for ST-Ericsson.
+ *
+ *  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; version 2 of the License.
+ *
+ *  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
+ */
+
+#include "bluetooth.h"
+#include "log.h"
+
+#include "server.h"
+
+int sap_server_register(const char *path, bdaddr_t *src)
+{
+	DBG("Register SAP server.");
+	return 0;
+}
+
+int sap_server_unregister(const char *path)
+{
+	DBG("Unregister SAP server.");
+	return 0;
+}
+
+int sap_server_init(DBusConnection *conn)
+{
+	DBG("Init SAP server.");
+	return 0;
+}
+
+void sap_server_exit(void)
+{
+	DBG("Exit SAP server.");
+}
diff --git a/sap/server.h b/sap/server.h
new file mode 100644
index 0000000..ef2b7b8
--- /dev/null
+++ b/sap/server.h
@@ -0,0 +1,26 @@
+/*
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2010 ST-Ericsson SA
+ *
+ *  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
+ */
+
+#include <gdbus.h>
+
+int sap_server_init(DBusConnection *conn);
+void sap_server_exit(void);
+int sap_server_register(const char *path, bdaddr_t *src);
+int sap_server_unregister(const char *path);
-- 
1.7.0.4


^ permalink raw reply related

* Re: [PATCH 4/4] Sim Access Profile dummy driver
From: Johan Hedberg @ 2010-11-05 10:16 UTC (permalink / raw)
  To: Waldemar Rymarkiewicz; +Cc: linux-bluetooth, suraj, joakim.xj.ceder
In-Reply-To: <1288791271-13857-5-git-send-email-waldemar.rymarkiewicz@tieto.com>

Hi Waldek,

On Wed, Nov 03, 2010, Waldemar Rymarkiewicz wrote:
> +static sim_connection_status_t sim_card_connection_status = SIM_DISCONNECTED;

Consider shortening these names. At least one of them (either the type
or the variable).

> +static void *		sap_data = NULL;  /* SAP server private data.*/

No whitespace between * and sap_data. Why is this void instead of a
specific type when its static and therefore wont be seen by other
modules?

> +	if(sim_card_connection_status == SIM_MISSING)

Space before (

> +	}else if(sim_card_connection_status != SIM_CONNECTED)

Space after } and before (

> +		sap_power_sim_on_rsp(sap_device, SAP_RESULT_ERROR_NOT_ACCESSIBLE);
> +	else {
> +		sap_power_sim_on_rsp(sap_device, SAP_RESULT_ERROR_NO_REASON);
> +	}

Why do you have {} for one branch but not for the other? In general
one-line branches/scopes shouldn't have braces, though the kernel coding
guideline does allow them if at least one part of the same if-else
statement has them.

> +static inline DBusMessage *invalid_args(DBusMessage *msg)

Never mind the previous comment I had about this. I checked the rest of
the tree and it seems this inline convention for D-Bus error generating
functions is quite common (though imho might not be needed at all).

> +	if(sim_card_connection_status != SIM_CONNECTED)

Space before (

> +}
> +
> +
> +static GDBusMethodTable dummy_methods[] = {

Remove the other empty line.

> +	{ "OngoingCall",	"b",	"",	ongoing_call},
> +	{ "MaxMessageSize",	"u",	"",	max_msg_size},
> +	{ "Disconnect",		"",	"",	disconnect},
> +	{ "CardStatus",		"u",	"",	card_status},
> +	{ }

> +static GDBusSignalTable dummy_signals[] = {
> +	{ "","" },
> +	{ }
> +};

If you have no signals just pass NULL to g_dbus_register_interface
instead of declaring an (almost) empty table. Also, "" isn't a valid
value for the signal name.

Johan

^ permalink raw reply

* Re: [PATCH 3/4] Sim Access Profile Server
From: Johan Hedberg @ 2010-11-05 10:05 UTC (permalink / raw)
  To: Waldemar Rymarkiewicz; +Cc: linux-bluetooth, suraj, joakim.xj.ceder
In-Reply-To: <1288791271-13857-4-git-send-email-waldemar.rymarkiewicz@tieto.com>

Hi Waldek,

On Wed, Nov 03, 2010, Waldemar Rymarkiewicz wrote:
> +	uint8_t atr[] = {0x3b, 0x9a, 0x96, 0x00, 0x92, 0x01, 0x98, 0x93, 0x17,

Space after {

> +			 0x00, 0x02, 0x28, 0x03, 0x00};

Mixed spaces and tabs for indentation. Just use tabs. Space before }

> +void sap_transfer_card_reader_status_req(void * sap_device)

No space between * and sap_device

> +void sap_set_transport_protocol_req(void * sap_device,sap_parameter * param)

White space again. It should be "void *sap_device, sap_parameter *param)"

> + *  Copyright (C) 2010 Claudio Takahasi<claudio.takahasi@openbossa.org>

Same copyright issue as previously discussed.

> +/* Connection Status - SAP v1.1 section 5.2.2 */
> +typedef enum {
> +	SAP_STATUS_OK 				= 0x00,

There's an extra space after OK. Just use tabs.

> +/* Result codes - SAP v1.1 section 5.2.4 */
> +typedef enum {
> +	SAP_RESULT_OK 			= 0x00,

Same here.

> +/* Status Change - SAP v1.1 section 5.2.8 */
> +typedef enum {
> +	SAP_STATUS_CHANGE_UNKNOWN_ERROR	= 0x00,
> +	SAP_STATUS_CHANGE_CARD_RESET	= 0x01,
> +	SAP_STATUS_CHANGE_CARD_NOT_ACCESSIBLE = 0x02,
> +	SAP_STATUS_CHANGE_CARD_REMOVED	= 0x03,
> +	SAP_STATUS_CHANGE_CARD_INSERTED	= 0x04,
> +	SAP_STATUS_CHANGE_CARD_RECOVERED = 0x05
> +} sap_status_change_t;

Why don't you use similar alignmenth here as for the other enums?

> +/* Message format - SAP v1.1 section 5.1 */
> +typedef struct {

Please don't use typedefs with structs. 

> +} __attribute__ ((packed)) sap_message;
> +
> +
> +typedef enum {

Remove one of the consequtive empty lines.

> +} icc_reader_status_t;
> +
> +
> +#define SAP_BUF_SIZE		512

Same here.

> +/*SAP responses to SAP requests. Implemented by server.c */
> +int sap_connect_rsp(void *sap_device, sap_status_t status, uint16_t maxmsgsize);
> +int sap_disconnect_rsp(void *sap_device);
> +int sap_transfer_apdu_rsp(void *sap_device, sap_result_t result, uint8_t *sap_apdu_resp, uint16_t length);
> +int sap_transfer_atr_rsp(void *sap_device, sap_result_t result, uint8_t *sap_atr, uint16_t length);
> +int sap_power_sim_off_rsp(void *sap_device, sap_result_t result);
> +int sap_power_sim_on_rsp(void *sap_device, sap_result_t result);
> +int sap_reset_sim_rsp(void *sap_device, sap_result_t result);
> +int sap_transfer_card_reader_status_rsp(void *sap_device, sap_result_t result, icc_reader_status_t status);
> +int sap_error_rsp(void *sap_device);
> +int sap_transport_protocol_rsp(void *sap_device, sap_result_t result);

Several of the above lines go beyond 79 columns. Please split them.

> +++ b/sap/server.c
> @@ -2,7 +2,9 @@
>   *  BlueZ - Bluetooth protocol stack for Linux
>   *
>   *  Copyright (C) 2010 ST-Ericsson SA
> + *  Copyright (C) 2010 Claudio Takahasi<claudio.takahasi@openbossa.org>

Same copyright issue as before.

> +static void connect_req(void *data, sap_parameter *param);
> +static int disconnect_req(void *data, sap_disconnection_type_t disc_type);
> +static void transfer_apdu_req(void *data, sap_parameter *param);
> +static void transfer_atr_req(void *data);
> +static void power_sim_off_req(void *data);
> +static void power_sim_on_req(void *data);
> +static void reset_sim_req(void *data);
> +static void transfer_card_reader_status_req(void *data);
> +static void set_transport_protocol_req(void *data, sap_parameter *param);
> +static int disconnect_ind(void *sap_device, sap_disconnection_type_t type);

Are all these forward-declarations really needed? If you can avoid them
by sorting the functions within the c file differently, please do so.

> +static gsize add_result_parameter(sap_result_t result, sap_parameter *param);

Use size_t instead of gsize.

> +}
> +
> +
> +static inline int is_power_sim_off_req_allowed(uint8_t processing_req)

Remove one of the consecutive empty lines. Remove the "inline" unless
you really profiled this and discovered that this has a measurable
impact and that the compiler fails to optimize this without the
"inline".

> +	switch(processing_req) {

Space before )

> +static inline int is_reset_sim_req_allowed(uint8_t processing_req)
> +{
> +	switch(processing_req) {

Same here.

> +static int check_msg(sap_message *msg)
> +{
> +	if(!msg)

And here.

> +}
> +
> +
> +static void start_guard_timer(struct sap_server *server, guint interval)

Remove one of the empty lines.

> +{
> +	if(!server)

Space before (

> +	switch(server->state) {

Same here.

> +	if(!server || !buf)

And here.

> +	if(written != (gsize)size) {

And here.

> +		error("send_message:write error. written %d size %d", written, size);
> +	}
> +	DBG("send_message: written=%x",(unsigned int)written);

Empty line after }

> +	if(!server || !param)

Space before (

> +	val = (uint16_t *) &param->val;
> +	maxmsgsize = ntohs(*val);

Is this unaligned access safe?

> +	if (maxmsgsize <= SAP_BUF_SIZE){
> +		server->processing_req = SAP_CONNECT_REQ;
> +		sap_connect_req(server, maxmsgsize);
> +	}else{

Space before and after else

> +	if(!server)

Space before (

> +	switch(disc_type) {

Same here.

> +static void transfer_apdu_req(void * data, sap_parameter * param)

No spaces after *

> +	if(!server || !param)

Space before (

> +}
> +
> +
> +static void transfer_atr_req(void * data)

Remove one of the empty lines. No space before data.

> +	if(!server)

Space before (

> +}
> +
> +
> +static void power_sim_off_req(void *data)

Remove one of the empty lines.

> +	if(!server)

Space before (

> +static void power_sim_on_req(void *data)
> +{
> +	struct sap_server *server = data;
> +
> +	if(!server)

Space before (

> +static void reset_sim_req(void *data)
> +{
> +	struct sap_server *server = data;
> +
> +	if(!server)

Same here.

> +static void transfer_card_reader_status_req(void * data)

No space before data.

> +{
> +	struct sap_server *server = data;
> +
> +	if(!server)

Space before (

> +static void set_transport_protocol_req(void *data, sap_parameter *param)
> +{
> +	struct sap_server *server = data;
> +
> +	if(!server || !param)

Same here.

> +	gchar buf[SAP_BUF_SIZE];

Use char instead of gchar.

> +	gsize size = sizeof(sap_message);

Use size_t instead of gsize.

> +	if(!server)

Space before (

> +int sap_connect_rsp(void *sap_device, sap_status_t status, uint16_t maxmsgsize)
> +{
> +	struct sap_server *server = sap_device;
> +	gchar buf[SAP_BUF_SIZE];
> +	sap_message *msg = (sap_message *) buf;
> +	sap_parameter *param = (sap_parameter *) msg->param;
> +	gsize size = sizeof(sap_message);

size_t

> +	if(!server)

Space before (

> +	if (server->state != SAP_STATE_CONNECT_IN_PROGRESS) {
> +		return -EPERM;
> +	}

{} not needed for one-line scopes.

> +int sap_disconnect_rsp(void *sap_device)
> +{
> +	struct sap_server *server = sap_device;
> +	sap_message msg = {0};

Space before and after 0

> +	if(!server)

Space before (

> +	gchar buf[SAP_BUF_SIZE] = {0};

Use char instead of gchar. Is the initialization upon declaration really
necessary?

> +	gsize size = sizeof(sap_message);

sizt_t

> +	if(!server)

Space before (

> +int sap_transfer_atr_rsp(void *sap_device, sap_result_t result, uint8_t *atr,
> +								uint16_t length)
> +{
> +	struct sap_server *server = sap_device;
> +	gchar buf[SAP_BUF_SIZE]= {0};
> +	sap_message *msg = (sap_message *) buf;
> +	sap_parameter *param = (sap_parameter *) msg->param;
> +	gsize size = sizeof(sap_message);
> +
> +	if(!server)
> +		return -1;

Same comments as for the previous function.

> +int sap_power_sim_off_rsp(void *sap_device, sap_result_t result)
> +{
> +	struct sap_server *server = sap_device;
> +	gchar buf[SAP_BUF_SIZE] = {0};
> +	sap_message *msg = (sap_message *) buf;
> +	gsize size = sizeof(sap_message);
> +
> +	if(!server)
> +		return -1;

Same here.

> +int sap_power_sim_on_rsp(void *sap_device, sap_result_t result)
> +{
> +	struct sap_server *server = sap_device;
> +	gchar buf[SAP_BUF_SIZE] = {0};
> +	sap_message *msg = (sap_message *) buf;
> +	gsize size = sizeof(sap_message);
> +
> +	if(!server)
> +		return -1;

And here.

> +int sap_reset_sim_rsp(void *sap_device, sap_result_t result)
> +{
> +	struct sap_server *server = sap_device;
> +	gchar buf[SAP_BUF_SIZE] = {0};
> +	sap_message *msg = (sap_message *) buf;
> +	gsize size = sizeof(sap_message);
> +
> +	if(!server)
> +		return -1;

And here.

> +int sap_transfer_card_reader_status_rsp(void *sap_device, sap_result_t result,
> +						icc_reader_status_t status)
> +{
> +	struct sap_server *server = sap_device;
> +	gchar buf[SAP_BUF_SIZE] = {0};
> +	sap_message *msg = (sap_message *) buf;
> +	sap_parameter *param = (sap_parameter *) msg->param;
> +	gsize size = sizeof(sap_message);
> +
> +	if(!server)
> +		return -1;

And here.

> +int sap_transport_protocol_rsp(void *sap_device, sap_result_t result)
> +{
> +	struct sap_server *server = sap_device;
> +	gchar buf[SAP_BUF_SIZE] = {0};
> +	sap_message *msg = (sap_message *) buf;
> +	gsize size = sizeof(sap_message);
> +
> +	if(!server)
> +		return -1;

And here.

> +int sap_error_rsp(void *sap_device)
> +{
> +	sap_message msg;
> +
> +	memset(&msg, 0, sizeof(msg));
> +	msg.id = SAP_ERROR_RESP;
> +
> +	return send_message(sap_device, (gchar *) &msg, sizeof(msg));

char instead of gchar. Worth considering if the second parameter to
send_message should be void * to avoid these type casts.

> +int sap_status_ind(void *sap_device, sap_status_change_t status_change)
> +{
> +	struct sap_server *server = sap_device;
> +	gchar buf[SAP_BUF_SIZE] = {0};
> +	sap_message *msg = (sap_message *) buf;
> +	sap_parameter *param = (sap_parameter *) msg->param;
> +	gsize size = sizeof(sap_message);
> +
> +	if(!server)
> +		return -1;

Same comments as for the few other functions above.

> +		/*Don't propagate status indication if client is not connected */

Space before D

> +static int handle_cmd(void *data, gchar *buf, gsize size)

char instead of gchar, size_t instead of gsize

> +	sap_message *msg = (sap_message *) buf;

Maybe the function should take void * so you don't need the explicit
type cast?

> +	switch(msg->id) {

Space befor e(

> +		case SAP_CONNECT_REQ:

Incorrect indentation. This should have the same as the initial switch
line. Same goes for all other case statements.

> +static gboolean sap_io_cb(GIOChannel *chan, GIOCondition cond, void *data)
> +{
> +	gchar buf[SAP_BUF_SIZE];
> +	gsize bytes_read = 0;

char and size_t

> +	if (handle_cmd(data, buf, bytes_read) < 0) {
> +		error("Invalid SAP message.");
> +	}

No {} for one-line scopes.

> +	if(!server)

Space before (

> +	g_io_add_watch_full(chan, G_PRIORITY_DEFAULT,
> +			G_IO_IN | G_IO_ERR | G_IO_HUP| G_IO_NVAL,
> +			(GIOFunc) sap_io_cb, server, sap_io_destroy);

Instead of type casting to GIOFunc just fix sap_io_cp to have the right
type and then do necessary assignments to correct variable types inside
that function.

> +	if(!server || !server->io)

Space before (

> +	if (!bt_io_accept(server->io, sap_connect_cb, server, NULL, &gerr)) {
> +		error("bt_io_accept: %s", gerr->message);
> +		g_error_free(gerr);
> +		goto drop;
> +	}
> +	return;

Empty line before return

> +	if(!chan || !server)

Space before (

> +	DBG("SAP incoming connection (sock %d) authorization.", g_io_channel_unix_get_fd(chan));

Too long line.

> +}
> +
> +
> +

Three empty lines? :)

> +static inline DBusMessage *message_failed(DBusMessage *msg,

Remove the inline unless you've really done the profiling and concluded
that it's necessary.

> +	sdp_record_t *record = NULL;
> +	GIOChannel *io = NULL;

Unnecessary initialization since the variables gets unconditionally
initialized before usage in the function. Pay attention to this kind of
stuff everywhere in your code and fix other places too in case I missed
them.

> +	io = bt_io_listen(BT_IO_RFCOMM, NULL, connect_confirm_cb, server, NULL, &gerr,

Looks like that one goes over 79 columns.

> +static DBusMessage *disable(DBusConnection *conn,
> +				DBusMessage *msg, void *data)

Looks like at least the DBusMessage parameter would still fit on the
previous line.

> +	DBusMessage *reply = NULL;

Unnecessary initialization upon declaration.

> +	if(!server)

Space before (

> +static DBusMessage *disconnect(DBusConnection *conn, DBusMessage *msg, void *data)

Looks like that goes over 79 columns.

> +	server = g_new0(struct sap_server, 1);
> +
> +	if (!server) {

g_new0 is guaranteed to succeed or call abort(). It will never return
NULL. If you really want to have the possibility for checking for
allocation errors use the g_try_new variants.

Johan

^ permalink raw reply

* Re: [PATCH 2/4] Sim Access Profile Manager
From: Johan Hedberg @ 2010-11-05  9:30 UTC (permalink / raw)
  To: Waldemar Rymarkiewicz; +Cc: linux-bluetooth, suraj, joakim.xj.ceder
In-Reply-To: <1288791271-13857-3-git-send-email-waldemar.rymarkiewicz@tieto.com>

Hi Waldek,

On Wed, Nov 03, 2010, Waldemar Rymarkiewicz wrote:
> +++ b/sap/main.c
> @@ -0,0 +1,54 @@
> +/*
> + *  BlueZ - Bluetooth protocol stack for Linux
> + *
> + *  Copyright (C) 2010 Claudio Takahasi<claudio.takahasi@openbossa.org>

As discussed off-list, this needs fixing.

> +++ b/sap/manager.c
> @@ -0,0 +1,94 @@
> +/*
> + *  BlueZ - Bluetooth protocol stack for Linux
> + *
> + *  Copyright (C) 2010 Claudio Takahasi<claudio.takahasi@openbossa.org>

Same here.

> +static DBusConnection *connection = NULL;
> +
> +
> +static int sap_server_probe(struct btd_adapter *adapter)

There should never be the need to have two consecutive empty lines.
Please remove one.

> +	const gchar *path = adapter_get_path(adapter);

Please avoid using the glib specific types when standard C types can be
used. I.e. use just "char" here.

> +static void sap_server_remove(struct btd_adapter *adapter)
> +{
> +	const gchar *path = adapter_get_path(adapter);

Same here.

> +++ b/sap/manager.h
> @@ -0,0 +1,21 @@
> +/*
> + *  BlueZ - Bluetooth protocol stack for Linux
> + *
> + *  Copyright (C) 2010 Claudio Takahasi<claudio.takahasi@openbossa.org>

Same copyright fix needed as previously discussed.

> +++ b/sap/server.h
> @@ -0,0 +1,25 @@
> +/*
> + *  BlueZ - Bluetooth protocol stack for Linux
> + *
> + *  Copyright (C) 2010 Claudio Takahasi<claudio.takahasi@openbossa.org>

Same here.

Johan

^ permalink raw reply

* Re: [PATCH] Fix add disconnect watch in connecting state
From: Johan Hedberg @ 2010-11-05  9:18 UTC (permalink / raw)
  To: Daniel Örstadius; +Cc: linux-bluetooth
In-Reply-To: <AANLkTimKWv3XcJ6qfJK6QNCY38vza+Nj12cGfdAELXxu@mail.gmail.com>

Hi Daniel,

On Fri, Nov 05, 2010, Daniel Örstadius wrote:
> On Thu, Nov 4, 2010 at 8:16 PM, Johan Hedberg <johan.hedberg@gmail.com> wrote:
> > This doesn't seem quite right to me. Aren't you now adding a disconnect
> > callback twice: once for CONNECTING and a second time for CONNECTED? It
> > seems like you should only add it when new_state == CONNECTING, right?
> >
> 
> Yes, that seems right, attaching updated patch.

Thanks. The patch is now in the upstream tree.

Johan

^ permalink raw reply

* Re: [PATCH] Fix add disconnect watch in connecting state
From: Daniel Örstadius @ 2010-11-05  8:59 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <20101104181606.GA15745@jh-x301>

[-- Attachment #1: Type: text/plain, Size: 360 bytes --]

On Thu, Nov 4, 2010 at 8:16 PM, Johan Hedberg <johan.hedberg@gmail.com> wrote:
> This doesn't seem quite right to me. Aren't you now adding a disconnect
> callback twice: once for CONNECTING and a second time for CONNECTED? It
> seems like you should only add it when new_state == CONNECTING, right?
>

Yes, that seems right, attaching updated patch.

/Daniel

[-- Attachment #2: 0001-Fix-add-disconnect-watch-in-connecting-state.patch --]
[-- Type: text/x-patch, Size: 948 bytes --]

From e42ce63878f368893e5e119d27a5477dd430f9ae Mon Sep 17 00:00:00 2001
From: Daniel Orstadius <daniel.orstadius@nokia.com>
Date: Fri, 5 Nov 2010 10:49:41 +0200
Subject: [PATCH] Fix add disconnect watch in connecting state

If disconnect_cb is not added until the connected state, the
callback will not be triggered if Device.Disconnected is called
while the audio profiles are still connecting.
---
 audio/device.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/audio/device.c b/audio/device.c
index 9554c7b..eff8231 100644
--- a/audio/device.c
+++ b/audio/device.c
@@ -231,7 +231,7 @@ static void device_set_state(struct audio_device *dev, audio_state_t new_state)
 							priv->dc_id);
 			priv->dc_id = 0;
 		}
-	} else if (new_state == AUDIO_STATE_CONNECTED)
+	} else if (new_state == AUDIO_STATE_CONNECTING)
 		priv->dc_id = device_add_disconnect_watch(dev->btd_dev,
 						disconnect_cb, dev, NULL);
 
-- 
1.6.0.4


^ permalink raw reply related

* Re: [PATCH] Move gattrib source files to src directory
From: Johan Hedberg @ 2010-11-05  5:06 UTC (permalink / raw)
  To: Claudio Takahasi; +Cc: linux-bluetooth, marcel
In-Reply-To: <1288901266-32547-1-git-send-email-claudio.takahasi@openbossa.org>

Hi Claudio,

On Thu, Nov 04, 2010, Claudio Takahasi wrote:
> gattrib related functions will be required during the device creation
> for GATT enabled devices(BR/EDR and LE). Primary service discovery is
> a pre-condition to probe the GATT device driver.
> ---
>  Makefile.am      |    7 +-
>  attrib/att.c     |  764 ------------------------------------------------------
>  attrib/att.h     |  206 ---------------
>  attrib/gatt.c    |  113 --------
>  attrib/gatt.h    |   43 ---
>  attrib/gattrib.c |  535 --------------------------------------
>  attrib/gattrib.h |   72 -----
>  src/att.c        |  764 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  src/att.h        |  206 +++++++++++++++
>  src/gatt.c       |  113 ++++++++
>  src/gatt.h       |   43 +++
>  src/gattrib.c    |  535 ++++++++++++++++++++++++++++++++++++++
>  src/gattrib.h    |   72 +++++
>  13 files changed, 1736 insertions(+), 1737 deletions(-)
>  delete mode 100644 attrib/att.c
>  delete mode 100644 attrib/att.h
>  delete mode 100644 attrib/gatt.c
>  delete mode 100644 attrib/gatt.h
>  delete mode 100644 attrib/gattrib.c
>  delete mode 100644 attrib/gattrib.h
>  create mode 100644 src/att.c
>  create mode 100644 src/att.h
>  create mode 100644 src/gatt.c
>  create mode 100644 src/gatt.h
>  create mode 100644 src/gattrib.c
>  create mode 100644 src/gattrib.h

I'll wait a little bit with this one. I agree that the gattrib
funcionality needs to be available within the core daemon, but does that
necessarily mean that the source files for need to be in src? It'd be
good to get some comment from Marcel about this too.

Johan

^ permalink raw reply

* Re: [PATCH] Fix invalid reference to GATT service structure
From: Johan Hedberg @ 2010-11-05  5:03 UTC (permalink / raw)
  To: Claudio Takahasi; +Cc: linux-bluetooth
In-Reply-To: <1288899810-18722-3-git-send-email-claudio.takahasi@openbossa.org>

Hi Claudio,

On Thu, Nov 04, 2010, Claudio Takahasi wrote:
> ---
>  attrib/client.c |    9 ++++-----
>  1 files changed, 4 insertions(+), 5 deletions(-)

This one has also been pushed upstream. Thanks.

Johan

^ permalink raw reply

* Re: [PATCH] Enable GATT over LE link on the attribute client
From: Johan Hedberg @ 2010-11-05  5:03 UTC (permalink / raw)
  To: Claudio Takahasi; +Cc: linux-bluetooth
In-Reply-To: <1288899810-18722-2-git-send-email-claudio.takahasi@openbossa.org>

Hi Claudio,

On Thu, Nov 04, 2010, Claudio Takahasi wrote:
> ---
>  attrib/client.c   |   22 ++++++++++++----------
>  attrib/gatt.h     |    2 ++
>  attrib/gatttool.c |    1 -
>  3 files changed, 14 insertions(+), 11 deletions(-)

Pushed upstream. Thanks.

Johan

^ permalink raw reply

* Re: [PATCH] Move set_nonblocking function to audio/unix.c
From: Johan Hedberg @ 2010-11-05  5:02 UTC (permalink / raw)
  To: Claudio Takahasi; +Cc: linux-bluetooth
In-Reply-To: <1288899810-18722-1-git-send-email-claudio.takahasi@openbossa.org>

Hi Claudio,

On Thu, Nov 04, 2010, Claudio Takahasi wrote:
> ---
>  audio/unix.c      |   20 ++++++++++++++++++++
>  src/glib-helper.c |   20 --------------------
>  src/glib-helper.h |    2 --
>  3 files changed, 20 insertions(+), 22 deletions(-)

Pushed upstream. Thanks.

Johan

^ permalink raw reply

* [PATCH] Move gattrib source files to src directory
From: Claudio Takahasi @ 2010-11-04 20:07 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Claudio Takahasi

gattrib related functions will be required during the device creation
for GATT enabled devices(BR/EDR and LE). Primary service discovery is
a pre-condition to probe the GATT device driver.
---
 Makefile.am      |    7 +-
 attrib/att.c     |  764 ------------------------------------------------------
 attrib/att.h     |  206 ---------------
 attrib/gatt.c    |  113 --------
 attrib/gatt.h    |   43 ---
 attrib/gattrib.c |  535 --------------------------------------
 attrib/gattrib.h |   72 -----
 src/att.c        |  764 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/att.h        |  206 +++++++++++++++
 src/gatt.c       |  113 ++++++++
 src/gatt.h       |   43 +++
 src/gattrib.c    |  535 ++++++++++++++++++++++++++++++++++++++
 src/gattrib.h    |   72 +++++
 13 files changed, 1736 insertions(+), 1737 deletions(-)
 delete mode 100644 attrib/att.c
 delete mode 100644 attrib/att.h
 delete mode 100644 attrib/gatt.c
 delete mode 100644 attrib/gatt.h
 delete mode 100644 attrib/gattrib.c
 delete mode 100644 attrib/gattrib.h
 create mode 100644 src/att.c
 create mode 100644 src/att.h
 create mode 100644 src/gatt.c
 create mode 100644 src/gatt.h
 create mode 100644 src/gattrib.c
 create mode 100644 src/gattrib.h

diff --git a/Makefile.am b/Makefile.am
index 873f2df..47e2740 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -87,8 +87,8 @@ sbc_sbctest_CFLAGS = @SNDFILE_CFLAGS@
 endif
 endif
 
-attrib_sources = attrib/att.h attrib/att.c attrib/gatt.h attrib/gatt.c \
-		attrib/gattrib.h attrib/gattrib.c
+attrib_sources = src/att.h src/att.c src/gatt.h src/gatt.c \
+		src/gattrib.h src/gattrib.c
 
 gdbus_sources = gdbus/gdbus.h gdbus/mainloop.c gdbus/watch.c \
 					gdbus/object.c gdbus/polkit.c
@@ -176,8 +176,7 @@ endif
 if ATTRIBPLUGIN
 bin_PROGRAMS += attrib/gatttool
 
-attrib_gatttool_SOURCES = attrib/gatttool.c attrib/att.c attrib/gatt.c \
-			  attrib/gattrib.c btio/btio.c
+attrib_gatttool_SOURCES = attrib/gatttool.c $(attrib_sources) btio/btio.c
 attrib_gatttool_LDADD = lib/libbluetooth.la @GLIB_LIBS@
 
 builtin_modules += attrib
diff --git a/attrib/att.c b/attrib/att.c
deleted file mode 100644
index fe41d0e..0000000
--- a/attrib/att.c
+++ /dev/null
@@ -1,764 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2010  Nokia Corporation
- *  Copyright (C) 2010  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  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
- *
- */
-
-#include <errno.h>
-#include <stdint.h>
-#include <stdlib.h>
-
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/sdp.h>
-#include <bluetooth/sdp_lib.h>
-
-#include "att.h"
-
-const char *att_ecode2str(uint8_t status)
-{
-	switch (status)  {
-	case ATT_ECODE_INVALID_HANDLE:
-		return "Invalid handle";
-	case ATT_ECODE_READ_NOT_PERM:
-		return "Atribute can't be read";
-	case ATT_ECODE_WRITE_NOT_PERM:
-		return "Attribute can't be written";
-	case ATT_ECODE_INVALID_PDU:
-		return "Attribute PDU was invalid";
-	case ATT_ECODE_INSUFF_AUTHEN:
-		return "Attribute requires authentication before read/write";
-	case ATT_ECODE_REQ_NOT_SUPP:
-		return "Server doesn't support the request received";
-	case ATT_ECODE_INVALID_OFFSET:
-		return "Offset past the end of the attribute";
-	case ATT_ECODE_INSUFF_AUTHO:
-		return "Attribute requires authorization before read/write";
-	case ATT_ECODE_PREP_QUEUE_FULL:
-		return "Too many prepare writes have been queued";
-	case ATT_ECODE_ATTR_NOT_FOUND:
-		return "No attribute found within the given range";
-	case ATT_ECODE_ATTR_NOT_LONG:
-		return "Attribute can't be read/written using Read Blob Req";
-	case ATT_ECODE_INSUFF_ENCR_KEY_SIZE:
-		return "Encryption Key Size is insufficient";
-	case ATT_ECODE_INVAL_ATTR_VALUE_LEN:
-		return "Attribute value length is invalid";
-	case ATT_ECODE_UNLIKELY:
-		return "Request attribute has encountered an unlikely error";
-	case ATT_ECODE_INSUFF_ENC:
-		return "Encryption required before read/write";
-	case ATT_ECODE_UNSUPP_GRP_TYPE:
-		return "Attribute type is not a supported grouping attribute";
-	case ATT_ECODE_INSUFF_RESOURCES:
-		return "Insufficient Resources to complete the request";
-	case ATT_ECODE_IO:
-		return "Internal application error: I/O";
-	default:
-		return "Unexpected error code";
-	}
-}
-
-void att_data_list_free(struct att_data_list *list)
-{
-	int i;
-
-	for (i = 0; i < list->num; i++)
-		free(list->data[i]);
-
-	free(list->data);
-	free(list);
-}
-
-uint16_t enc_read_by_grp_req(uint16_t start, uint16_t end, uuid_t *uuid,
-							uint8_t *pdu, int len)
-{
-	const uint16_t min_len = sizeof(pdu[0]) + sizeof(start) + sizeof(end);
-	uint16_t length;
-
-	if (!uuid)
-		return 0;
-
-	if (uuid->type == SDP_UUID16)
-		length = 2;
-	else if (uuid->type == SDP_UUID128)
-		length = 16;
-	else
-		return 0;
-
-	if (len < min_len + length)
-		return 0;
-
-	pdu[0] = ATT_OP_READ_BY_GROUP_REQ;
-	att_put_u16(start, &pdu[1]);
-	att_put_u16(end, &pdu[3]);
-
-	if (uuid->type == SDP_UUID16)
-		att_put_u16(uuid->value.uuid16, &pdu[5]);
-	else
-		memcpy(&pdu[5], &uuid->value.uuid128, length);
-
-	return min_len + length;
-}
-
-uint16_t dec_read_by_grp_req(const uint8_t *pdu, int len, uint16_t *start,
-						uint16_t *end, uuid_t *uuid)
-{
-	const uint16_t min_len = sizeof(pdu[0]) + sizeof(*start) + sizeof(*end);
-
-	if (pdu == NULL)
-		return 0;
-
-	if (start == NULL || end == NULL || uuid == NULL)
-		return 0;
-
-	if (pdu[0] != ATT_OP_READ_BY_GROUP_REQ)
-		return 0;
-
-	if (len < min_len + 2)
-		return 0;
-
-	*start = att_get_u16(&pdu[1]);
-	*end = att_get_u16(&pdu[3]);
-	if (len == min_len + 2)
-		sdp_uuid16_create(uuid, att_get_u16(&pdu[5]));
-	else
-		sdp_uuid128_create(uuid, &pdu[5]);
-
-	return len;
-}
-
-uint16_t enc_read_by_grp_resp(struct att_data_list *list, uint8_t *pdu,
-								int len)
-{
-	int i;
-	uint16_t w;
-	uint8_t *ptr;
-
-	if (list == NULL)
-		return 0;
-
-	if (len < list->len + 2)
-		return 0;
-
-	pdu[0] = ATT_OP_READ_BY_GROUP_RESP;
-	pdu[1] = list->len;
-
-	ptr = &pdu[2];
-
-	for (i = 0, w = 2; i < list->num && w + list->len <= len; i++) {
-		memcpy(ptr, list->data[i], list->len);
-		ptr += list->len;
-		w += list->len;
-	}
-
-	return w;
-}
-
-struct att_data_list *dec_read_by_grp_resp(const uint8_t *pdu, int len)
-{
-	struct att_data_list *list;
-	const uint8_t *ptr;
-	int i;
-
-	if (pdu[0] != ATT_OP_READ_BY_GROUP_RESP)
-		return NULL;
-
-	list = malloc(sizeof(struct att_data_list));
-	list->len = pdu[1];
-	list->num = (len - 2) / list->len;
-
-	list->data = malloc(sizeof(uint8_t *) * list->num);
-	ptr = &pdu[2];
-
-	for (i = 0; i < list->num; i++) {
-		list->data[i] = malloc(sizeof(uint8_t) * list->len);
-		memcpy(list->data[i], ptr, list->len);
-		ptr += list->len;
-	}
-
-	return list;
-}
-
-uint16_t enc_find_by_type_req(uint16_t start, uint16_t end, uuid_t *uuid,
-							uint8_t *pdu, int len)
-{
-	return 0;
-}
-
-uint16_t enc_read_by_type_req(uint16_t start, uint16_t end, uuid_t *uuid,
-							uint8_t *pdu, int len)
-{
-	const uint16_t min_len = sizeof(pdu[0]) + sizeof(start) + sizeof(end);
-	uint16_t length;
-
-	if (!uuid)
-		return 0;
-
-	if (uuid->type == SDP_UUID16)
-		length = 2;
-	else if (uuid->type == SDP_UUID128)
-		length = 16;
-	else
-		return 0;
-
-	if (len < min_len + length)
-		return 0;
-
-	pdu[0] = ATT_OP_READ_BY_TYPE_REQ;
-	att_put_u16(start, &pdu[1]);
-	att_put_u16(end, &pdu[3]);
-
-	if (uuid->type == SDP_UUID16)
-		att_put_u16(uuid->value.uuid16, &pdu[5]);
-	else
-		memcpy(&pdu[5], &uuid->value.uuid128, length);
-
-	return min_len + length;
-}
-
-uint16_t dec_read_by_type_req(const uint8_t *pdu, int len, uint16_t *start,
-						uint16_t *end, uuid_t *uuid)
-{
-	const uint16_t min_len = sizeof(pdu[0]) + sizeof(*start) + sizeof(*end);
-
-	if (pdu == NULL)
-		return 0;
-
-	if (start == NULL || end == NULL || uuid == NULL)
-		return 0;
-
-	if (len < min_len + 2)
-		return 0;
-
-	if (pdu[0] != ATT_OP_READ_BY_TYPE_REQ)
-		return 0;
-
-	*start = att_get_u16(&pdu[1]);
-	*end = att_get_u16(&pdu[3]);
-
-	if (len == min_len + 2)
-		sdp_uuid16_create(uuid, att_get_u16(&pdu[5]));
-	else
-		sdp_uuid128_create(uuid, &pdu[5]);
-
-	return len;
-}
-
-uint16_t enc_read_by_type_resp(struct att_data_list *list, uint8_t *pdu, int len)
-{
-	uint8_t *ptr;
-	int i, w;
-
-	if (list == NULL)
-		return 0;
-
-	if (pdu == NULL)
-		return 0;
-
-	if (len < list->len + 2)
-		return 0;
-
-	pdu[0] = ATT_OP_READ_BY_TYPE_RESP;
-	pdu[1] = list->len;
-	ptr = &pdu[2];
-
-	for (i = 0, w = 2; i < list->num && w + list->len <= len; i++) {
-		memcpy(ptr, list->data[i], list->len);
-		ptr += list->len;
-		w += list->len;
-	}
-
-	return w;
-}
-
-struct att_data_list *dec_read_by_type_resp(const uint8_t *pdu, int len)
-{
-	struct att_data_list *list;
-	const uint8_t *ptr;
-	int i;
-
-	if (pdu[0] != ATT_OP_READ_BY_TYPE_RESP)
-		return NULL;
-
-	list = malloc(sizeof(struct att_data_list));
-	list->len = pdu[1];
-	list->num = (len - 2) / list->len;
-
-	list->data = malloc(sizeof(uint8_t *) * list->num);
-	ptr = &pdu[2];
-
-	for (i = 0; i < list->num; i++) {
-		list->data[i] = malloc(sizeof(uint8_t) * list->len);
-		memcpy(list->data[i], ptr, list->len);
-		ptr += list->len;
-	}
-
-	return list;
-}
-
-uint16_t enc_write_cmd(uint16_t handle, const uint8_t *value, int vlen,
-							uint8_t *pdu, int len)
-{
-	const uint16_t min_len = sizeof(pdu[0]) + sizeof(handle);
-
-	if (pdu == NULL)
-		return 0;
-
-	if (len < min_len)
-		return 0;
-
-	if (vlen > len - min_len)
-		vlen = len - min_len;
-
-	pdu[0] = ATT_OP_WRITE_CMD;
-	att_put_u16(handle, &pdu[1]);
-
-	if (vlen > 0) {
-		memcpy(&pdu[3], value, vlen);
-		return min_len + vlen;
-	}
-
-	return min_len;
-}
-
-uint16_t dec_write_cmd(const uint8_t *pdu, int len, uint16_t *handle,
-						uint8_t *value, int *vlen)
-{
-	const uint16_t min_len = sizeof(pdu[0]) + sizeof(*handle);
-
-	if (pdu == NULL)
-		return 0;
-
-	if (value == NULL || vlen == NULL || handle == NULL)
-		return 0;
-
-	if (len < min_len)
-		return 0;
-
-	if (pdu[0] != ATT_OP_WRITE_CMD)
-		return 0;
-
-	*handle = att_get_u16(&pdu[1]);
-	memcpy(value, pdu + min_len, len - min_len);
-	*vlen = len - min_len;
-
-	return len;
-}
-
-uint16_t enc_write_req(uint16_t handle, const uint8_t *value, int vlen,
-							uint8_t *pdu, int len)
-{
-	const uint16_t min_len = sizeof(pdu[0]) + sizeof(handle);
-
-	if (pdu == NULL)
-		return 0;
-
-	if (len < min_len)
-		return 0;
-
-	if (vlen > len - min_len)
-		vlen = len - min_len;
-
-	pdu[0] = ATT_OP_WRITE_REQ;
-	att_put_u16(handle, &pdu[1]);
-
-	if (vlen > 0) {
-		memcpy(&pdu[3], value, vlen);
-		return min_len + vlen;
-	}
-
-	return min_len;
-}
-
-uint16_t dec_write_req(const uint8_t *pdu, int len, uint16_t *handle,
-						uint8_t *value, int *vlen)
-{
-	const uint16_t min_len = sizeof(pdu[0]) + sizeof(*handle);
-
-	if (pdu == NULL)
-		return 0;
-
-	if (value == NULL || vlen == NULL || handle == NULL)
-		return 0;
-
-	if (len < min_len)
-		return 0;
-
-	if (pdu[0] != ATT_OP_WRITE_REQ)
-		return 0;
-
-	*handle = att_get_u16(&pdu[1]);
-	*vlen = len - min_len;
-	if (*vlen > 0)
-		memcpy(value, pdu + min_len, *vlen);
-
-	return len;
-}
-
-uint16_t enc_read_req(uint16_t handle, uint8_t *pdu, int len)
-{
-	const uint16_t min_len = sizeof(pdu[0]) + sizeof(handle);
-
-	if (pdu == NULL)
-		return 0;
-
-	if (len < min_len)
-		return 0;
-
-	pdu[0] = ATT_OP_READ_REQ;
-	att_put_u16(handle, &pdu[1]);
-
-	return min_len;
-}
-
-uint16_t dec_read_req(const uint8_t *pdu, int len, uint16_t *handle)
-{
-	const uint16_t min_len = sizeof(pdu[0]) + sizeof(*handle);
-
-	if (pdu == NULL)
-		return 0;
-
-	if (handle == NULL)
-		return 0;
-
-	if (len < min_len)
-		return 0;
-
-	if (pdu[0] != ATT_OP_READ_REQ)
-		return 0;
-
-	*handle = att_get_u16(&pdu[1]);
-
-	return min_len;
-}
-
-uint16_t enc_read_resp(uint8_t *value, int vlen, uint8_t *pdu, int len)
-{
-	if (pdu == NULL)
-		return 0;
-
-	/* If the attribute value length is longer than the allowed PDU size,
-	 * send only the octets that fit on the PDU. The remaining octets can
-	 * be requested using the Read Blob Request. */
-	if (vlen > len - 1)
-		vlen = len - 1;
-
-	pdu[0] = ATT_OP_READ_RESP;
-
-	memcpy(pdu + 1, value, vlen);
-
-	return vlen + 1;
-}
-
-uint16_t dec_read_resp(const uint8_t *pdu, int len, uint8_t *value, int *vlen)
-{
-	if (pdu == NULL)
-		return 0;
-
-	if (value == NULL || vlen == NULL)
-		return 0;
-
-	if (pdu[0] != ATT_OP_READ_RESP)
-		return 0;
-
-	memcpy(value, pdu + 1, len - 1);
-
-	*vlen = len - 1;
-
-	return len;
-}
-
-uint16_t enc_error_resp(uint8_t opcode, uint16_t handle, uint8_t status,
-							uint8_t *pdu, int len)
-{
-	const uint16_t min_len = sizeof(pdu[0]) + sizeof(opcode) +
-						sizeof(handle) + sizeof(status);
-	uint16_t u16;
-
-	if (len < min_len)
-		return 0;
-
-	u16 = htobs(handle);
-	pdu[0] = ATT_OP_ERROR;
-	pdu[1] = opcode;
-	memcpy(&pdu[2], &u16, sizeof(u16));
-	pdu[4] = status;
-
-	return min_len;
-}
-
-uint16_t enc_find_info_req(uint16_t start, uint16_t end, uint8_t *pdu, int len)
-{
-	const uint16_t min_len = sizeof(pdu[0]) + sizeof(start) + sizeof(end);
-
-	if (pdu == NULL)
-		return 0;
-
-	if (len < min_len)
-		return 0;
-
-	pdu[0] = ATT_OP_FIND_INFO_REQ;
-	att_put_u16(start, &pdu[1]);
-	att_put_u16(end, &pdu[3]);
-
-	return min_len;
-}
-
-uint16_t dec_find_info_req(const uint8_t *pdu, int len, uint16_t *start,
-								uint16_t *end)
-{
-	const uint16_t min_len = sizeof(pdu[0]) + sizeof(*start) + sizeof(*end);
-
-	if (pdu == NULL)
-		return 0;
-
-	if (len < min_len)
-		return 0;
-
-	if (start == NULL || end == NULL)
-		return 0;
-
-	if (pdu[0] != ATT_OP_FIND_INFO_REQ)
-		return 0;
-
-	*start = att_get_u16(&pdu[1]);
-	*end = att_get_u16(&pdu[3]);
-
-	return min_len;
-}
-
-uint16_t enc_find_info_resp(uint8_t format, struct att_data_list *list,
-							uint8_t *pdu, int len)
-{
-	uint8_t *ptr;
-	int i, w;
-
-	if (pdu == NULL)
-		return 0;
-
-	if (list == NULL)
-		return 0;
-
-	if (len < list->len + 2)
-		return 0;
-
-	pdu[0] = ATT_OP_FIND_INFO_RESP;
-	pdu[1] = format;
-	ptr = (void *) &pdu[2];
-
-	for (i = 0, w = 2; i < list->num && w + list->len <= len; i++) {
-		memcpy(ptr, list->data[i], list->len);
-		ptr += list->len;
-		w += list->len;
-	}
-
-	return w;
-}
-
-struct att_data_list *dec_find_info_resp(const uint8_t *pdu, int len,
-							uint8_t *format)
-{
-	struct att_data_list *list;
-	uint8_t *ptr;
-	int i;
-
-	if (pdu == NULL)
-		return 0;
-
-	if (format == NULL)
-		return 0;
-
-	if (pdu[0] != ATT_OP_FIND_INFO_RESP)
-		return 0;
-
-	*format = pdu[1];
-
-	list = malloc(sizeof(struct att_data_list));
-
-	list->len = sizeof(pdu[0]) + sizeof(*format);
-	if (*format == 0x01)
-		list->len += 2;
-	else if (*format == 0x02)
-		list->len += 16;
-
-	list->num = (len - 2) / list->len;
-	list->data = malloc(sizeof(uint8_t *) * list->num);
-
-	ptr = (void *) &pdu[2];
-
-	for (i = 0; i < list->num; i++) {
-		list->data[i] = malloc(list->len);
-		memcpy(list->data[i], ptr, list->len);
-		ptr += list->len;
-	}
-
-	return list;
-}
-
-uint16_t enc_notification(struct attribute *a, uint8_t *pdu, int len)
-{
-	const uint16_t min_len = sizeof(pdu[0]) + sizeof(uint16_t);
-
-	if (pdu == NULL)
-		return 0;
-
-	if (len < (a->len + min_len))
-		return 0;
-
-	pdu[0] = ATT_OP_HANDLE_NOTIFY;
-	att_put_u16(a->handle, &pdu[1]);
-	memcpy(&pdu[3], a->data, a->len);
-
-	return a->len + min_len;
-}
-
-uint16_t enc_indication(struct attribute *a, uint8_t *pdu, int len)
-{
-	const uint16_t min_len = sizeof(pdu[0]) + sizeof(uint16_t);
-
-	if (pdu == NULL)
-		return 0;
-
-	if (len < (a->len + min_len))
-		return 0;
-
-	pdu[0] = ATT_OP_HANDLE_IND;
-	att_put_u16(a->handle, &pdu[1]);
-	memcpy(&pdu[3], a->data, a->len);
-
-	return a->len + min_len;
-}
-
-struct attribute *dec_indication(const uint8_t *pdu, int len)
-{
-	const uint16_t min_len = sizeof(pdu[0]) + sizeof(uint16_t);
-
-	struct attribute *a;
-
-	if (pdu == NULL)
-		return NULL;
-
-	if (pdu[0] != ATT_OP_HANDLE_IND)
-		return NULL;
-
-	if (len < min_len)
-		return NULL;
-
-	a = malloc(sizeof(struct attribute) + len - min_len);
-	if (a == NULL)
-		return NULL;
-
-	a->len = len - min_len;
-
-	a->handle = att_get_u16(&pdu[1]);
-	memcpy(a->data, &pdu[3], a->len);
-
-	return a;
-}
-
-uint16_t enc_confirmation(uint8_t *pdu, int len)
-{
-	const uint16_t min_len = sizeof(pdu[0]);
-
-	if (pdu == NULL)
-		return 0;
-
-	if (len < min_len)
-		return 0;
-
-	pdu[0] = ATT_OP_HANDLE_CNF;
-
-	return min_len;
-}
-
-uint16_t enc_mtu_req(uint16_t mtu, uint8_t *pdu, int len)
-{
-	const uint16_t min_len = sizeof(pdu[0]) + sizeof(mtu);
-
-	if (pdu == NULL)
-		return 0;
-
-	if (len < min_len)
-		return 0;
-
-	pdu[0] = ATT_OP_MTU_REQ;
-	att_put_u16(mtu, &pdu[1]);
-
-	return min_len;
-}
-
-uint16_t dec_mtu_req(const uint8_t *pdu, int len, uint16_t *mtu)
-{
-	const uint16_t min_len = sizeof(pdu[0]) + sizeof(*mtu);
-
-	if (pdu == NULL)
-		return 0;
-
-	if (mtu == NULL)
-		return 0;
-
-	if (len < min_len)
-		return 0;
-
-	if (pdu[0] != ATT_OP_MTU_REQ)
-		return 0;
-
-	*mtu = att_get_u16(&pdu[1]);
-
-	return min_len;
-}
-
-uint16_t enc_mtu_resp(uint16_t mtu, uint8_t *pdu, int len)
-{
-	const uint16_t min_len = sizeof(pdu[0]) + sizeof(mtu);
-
-	if (pdu == NULL)
-		return 0;
-
-	if (len < min_len)
-		return 0;
-
-	pdu[0] = ATT_OP_MTU_RESP;
-	att_put_u16(mtu, &pdu[1]);
-
-	return min_len;
-}
-
-uint16_t dec_mtu_resp(const uint8_t *pdu, int len, uint16_t *mtu)
-{
-	const uint16_t min_len = sizeof(pdu[0]) + sizeof(*mtu);
-
-	if (pdu == NULL)
-		return 0;
-
-	if (mtu == NULL)
-		return 0;
-
-	if (len < min_len)
-		return 0;
-
-	if (pdu[0] != ATT_OP_MTU_RESP)
-		return 0;
-
-	*mtu = att_get_u16(&pdu[1]);
-
-	return min_len;
-}
diff --git a/attrib/att.h b/attrib/att.h
deleted file mode 100644
index ea49dc2..0000000
--- a/attrib/att.h
+++ /dev/null
@@ -1,206 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2010  Nokia Corporation
- *  Copyright (C) 2010  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  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
- *
- */
-
-/* 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
-
-/* Attribute Protocol Opcodes */
-#define ATT_OP_ERROR			0x01
-#define ATT_OP_MTU_REQ			0x02
-#define ATT_OP_MTU_RESP			0x03
-#define ATT_OP_FIND_INFO_REQ		0x04
-#define ATT_OP_FIND_INFO_RESP		0x05
-#define ATT_OP_FIND_BY_TYPE_REQ		0x06
-#define ATT_OP_FIND_BY_TYPE_RESP	0x07
-#define ATT_OP_READ_BY_TYPE_REQ		0x08
-#define ATT_OP_READ_BY_TYPE_RESP	0x09
-#define ATT_OP_READ_REQ			0x0A
-#define ATT_OP_READ_RESP		0x0B
-#define ATT_OP_READ_BLOB_REQ		0x0C
-#define ATT_OP_READ_BLOB_RESP		0x0D
-#define ATT_OP_READ_MULTI_REQ		0x0E
-#define ATT_OP_READ_MULTI_RESP		0x0F
-#define ATT_OP_READ_BY_GROUP_REQ	0x10
-#define ATT_OP_READ_BY_GROUP_RESP	0x11
-#define ATT_OP_WRITE_REQ		0x12
-#define ATT_OP_WRITE_RESP		0x13
-#define ATT_OP_WRITE_CMD		0x52
-#define ATT_OP_PREP_WRITE_REQ		0x16
-#define ATT_OP_PREP_WRITE_RESP		0x17
-#define ATT_OP_EXEC_WRITE_REQ		0x18
-#define ATT_OP_EXEC_WRITE_RESP		0x19
-#define ATT_OP_HANDLE_NOTIFY		0x1B
-#define ATT_OP_HANDLE_IND		0x1D
-#define ATT_OP_HANDLE_CNF		0x1E
-#define ATT_OP_SIGNED_WRITE_CMD		0xD2
-
-/* Error codes for Error response PDU */
-#define ATT_ECODE_INVALID_HANDLE		0x01
-#define ATT_ECODE_READ_NOT_PERM			0x02
-#define ATT_ECODE_WRITE_NOT_PERM		0x03
-#define ATT_ECODE_INVALID_PDU			0x04
-#define ATT_ECODE_INSUFF_AUTHEN			0x05
-#define ATT_ECODE_REQ_NOT_SUPP			0x06
-#define ATT_ECODE_INVALID_OFFSET		0x07
-#define ATT_ECODE_INSUFF_AUTHO			0x08
-#define ATT_ECODE_PREP_QUEUE_FULL		0x09
-#define ATT_ECODE_ATTR_NOT_FOUND		0x0A
-#define ATT_ECODE_ATTR_NOT_LONG			0x0B
-#define ATT_ECODE_INSUFF_ENCR_KEY_SIZE		0x0C
-#define ATT_ECODE_INVAL_ATTR_VALUE_LEN		0x0D
-#define ATT_ECODE_UNLIKELY			0x0E
-#define ATT_ECODE_INSUFF_ENC			0x0F
-#define ATT_ECODE_UNSUPP_GRP_TYPE		0x10
-#define ATT_ECODE_INSUFF_RESOURCES		0x11
-/* Application error */
-#define ATT_ECODE_IO				0xFF
-
-/* Characteristic Property bit field */
-#define ATT_CHAR_PROPER_BROADCAST		0x01
-#define ATT_CHAR_PROPER_READ			0x02
-#define ATT_CHAR_PROPER_WRITE_WITHOUT_RESP	0x04
-#define ATT_CHAR_PROPER_WRITE			0x08
-#define ATT_CHAR_PROPER_NOTIFY			0x10
-#define ATT_CHAR_PROPER_INDICATE		0x20
-#define ATT_CHAR_PROPER_AUTH			0x40
-#define ATT_CHAR_PROPER_EXT_PROPER		0x80
-
-
-#define ATT_MAX_MTU				256
-#define ATT_DEFAULT_MTU				23
-
-struct attribute {
-	uint16_t handle;
-	uuid_t uuid;
-	int len;
-	uint8_t data[0];
-};
-
-struct att_data_list {
-	uint16_t num;
-	uint16_t len;
-	uint8_t **data;
-};
-
-/* These functions do byte conversion */
-static inline uint8_t att_get_u8(const void *ptr)
-{
-	const uint8_t *u8_ptr = ptr;
-	return bt_get_unaligned(u8_ptr);
-}
-
-static inline uint16_t att_get_u16(const void *ptr)
-{
-	const uint16_t *u16_ptr = ptr;
-	return btohs(bt_get_unaligned(u16_ptr));
-}
-
-static inline uint32_t att_get_u32(const void *ptr)
-{
-	const uint32_t *u32_ptr = ptr;
-	return btohl(bt_get_unaligned(u32_ptr));
-}
-
-static inline void att_put_u8(uint8_t src, void *dst)
-{
-	bt_put_unaligned(src, (uint8_t *) dst);
-}
-
-static inline void att_put_u16(uint16_t src, void *dst)
-{
-	bt_put_unaligned(htobs(src), (uint16_t *) dst);
-}
-
-static inline void att_put_u32(uint16_t src, void *dst)
-{
-	bt_put_unaligned(htobl(src), (uint32_t *) dst);
-}
-
-void att_data_list_free(struct att_data_list *list);
-
-const char *att_ecode2str(uint8_t status);
-uint16_t enc_read_by_grp_req(uint16_t start, uint16_t end, uuid_t *uuid,
-							uint8_t *pdu, int len);
-uint16_t dec_read_by_grp_req(const uint8_t *pdu, int len, uint16_t *start,
-						uint16_t *end, uuid_t *uuid);
-uint16_t enc_read_by_grp_resp(struct att_data_list *list, uint8_t *pdu, int len);
-uint16_t enc_find_by_type_req(uint16_t start, uint16_t end, uuid_t *uuid,
-							uint8_t *pdu, int len);
-struct att_data_list *dec_read_by_grp_resp(const uint8_t *pdu, int len);
-uint16_t enc_read_by_type_req(uint16_t start, uint16_t end, uuid_t *uuid,
-							uint8_t *pdu, int len);
-uint16_t dec_read_by_type_req(const uint8_t *pdu, int len, uint16_t *start,
-						uint16_t *end, uuid_t *uuid);
-uint16_t enc_read_by_type_resp(struct att_data_list *list, uint8_t *pdu,
-								int len);
-uint16_t enc_write_cmd(uint16_t handle, const uint8_t *value, int vlen,
-							uint8_t *pdu, int len);
-uint16_t dec_write_cmd(const uint8_t *pdu, int len, uint16_t *handle,
-						uint8_t *value, int *vlen);
-struct att_data_list *dec_read_by_type_resp(const uint8_t *pdu, int len);
-uint16_t enc_write_req(uint16_t handle, const uint8_t *value, int vlen,
-							uint8_t *pdu, int len);
-uint16_t dec_write_req(const uint8_t *pdu, int len, uint16_t *handle,
-						uint8_t *value, int *vlen);
-uint16_t enc_read_req(uint16_t handle, uint8_t *pdu, int len);
-uint16_t dec_read_req(const uint8_t *pdu, int len, uint16_t *handle);
-uint16_t enc_read_resp(uint8_t *value, int vlen, uint8_t *pdu, int len);
-uint16_t dec_read_resp(const uint8_t *pdu, int len, uint8_t *value, int *vlen);
-uint16_t enc_error_resp(uint8_t opcode, uint16_t handle, uint8_t status,
-							uint8_t *pdu, int len);
-uint16_t enc_find_info_req(uint16_t start, uint16_t end, uint8_t *pdu, int len);
-uint16_t dec_find_info_req(const uint8_t *pdu, int len, uint16_t *start,
-								uint16_t *end);
-uint16_t enc_find_info_resp(uint8_t format, struct att_data_list *list,
-							uint8_t *pdu, int len);
-struct att_data_list *dec_find_info_resp(const uint8_t *pdu, int len,
-							uint8_t *format);
-uint16_t enc_notification(struct attribute *a, uint8_t *pdu, int len);
-uint16_t enc_indication(struct attribute *a, uint8_t *pdu, int len);
-struct attribute *dec_indication(const uint8_t *pdu, int len);
-uint16_t enc_confirmation(uint8_t *pdu, int len);
-
-uint16_t enc_mtu_req(uint16_t mtu, uint8_t *pdu, int len);
-uint16_t dec_mtu_req(const uint8_t *pdu, int len, uint16_t *mtu);
-uint16_t enc_mtu_resp(uint16_t mtu, uint8_t *pdu, int len);
-uint16_t dec_mtu_resp(const uint8_t *pdu, int len, uint16_t *mtu);
diff --git a/attrib/gatt.c b/attrib/gatt.c
deleted file mode 100644
index 24ec990..0000000
--- a/attrib/gatt.c
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2010  Nokia Corporation
- *  Copyright (C) 2010  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  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
- *
- */
-
-#include <stdint.h>
-#include <glib.h>
-#include <bluetooth/sdp.h>
-#include <bluetooth/sdp_lib.h>
-
-#include "att.h"
-#include "gattrib.h"
-#include "gatt.h"
-
-guint gatt_discover_primary(GAttrib *attrib, uint16_t start,
-		uint16_t end, GAttribResultFunc func, gpointer user_data)
-{
-	uint8_t pdu[ATT_DEFAULT_MTU];
-	uuid_t uuid;
-	guint16 plen;
-
-	sdp_uuid16_create(&uuid, GATT_PRIM_SVC_UUID);
-
-	plen = enc_read_by_grp_req(start, end, &uuid, pdu, sizeof(pdu));
-	if (plen == 0)
-		return 0;
-
-	return g_attrib_send(attrib, ATT_OP_READ_BY_GROUP_REQ,
-					pdu, plen, func, user_data, NULL);
-}
-
-guint gatt_discover_char(GAttrib *attrib, uint16_t start, uint16_t end,
-				GAttribResultFunc func, gpointer user_data)
-{
-	uint8_t pdu[ATT_DEFAULT_MTU];
-	uuid_t uuid;
-	guint16 plen;
-
-	sdp_uuid16_create(&uuid, GATT_CHARAC_UUID);
-
-	plen = enc_read_by_type_req(start, end, &uuid, pdu, sizeof(pdu));
-	if (plen == 0)
-		return 0;
-
-	return g_attrib_send(attrib, ATT_OP_READ_BY_TYPE_REQ,
-					pdu, plen, func, user_data, NULL);
-}
-
-guint gatt_read_char(GAttrib *attrib, uint16_t handle, GAttribResultFunc func,
-							gpointer user_data)
-{
-	uint8_t pdu[ATT_DEFAULT_MTU];
-	guint16 plen;
-
-	plen = enc_read_req(handle, pdu, sizeof(pdu));
-	return g_attrib_send(attrib, ATT_OP_READ_REQ, pdu, plen, func,
-							user_data, NULL);
-}
-
-guint gatt_write_char(GAttrib *attrib, uint16_t handle, uint8_t *value,
-			int vlen, GAttribResultFunc func, gpointer user_data)
-{
-	uint8_t pdu[ATT_DEFAULT_MTU];
-	guint16 plen;
-
-	plen = enc_write_req(handle, value, vlen, pdu, sizeof(pdu));
-	return g_attrib_send(attrib, ATT_OP_WRITE_REQ, pdu, plen, func,
-							user_data, NULL);
-}
-
-guint gatt_find_info(GAttrib *attrib, uint16_t start, uint16_t end,
-				GAttribResultFunc func, gpointer user_data)
-{
-	uint8_t pdu[ATT_DEFAULT_MTU];
-	guint16 plen;
-
-	plen = enc_find_info_req(start, end, pdu, sizeof(pdu));
-	if (plen == 0)
-		return 0;
-
-	return g_attrib_send(attrib, ATT_OP_FIND_INFO_REQ, pdu, plen, func,
-							user_data, NULL);
-}
-
-guint gatt_write_cmd(GAttrib *attrib, uint16_t handle, uint8_t *value, int vlen,
-				GDestroyNotify notify, gpointer user_data)
-{
-	uint8_t pdu[ATT_DEFAULT_MTU];
-	guint16 plen;
-
-	plen = enc_write_cmd(handle, value, vlen, pdu, sizeof(pdu));
-	return g_attrib_send(attrib, ATT_OP_WRITE_CMD, pdu, plen, NULL,
-							user_data, notify);
-}
diff --git a/attrib/gatt.h b/attrib/gatt.h
deleted file mode 100644
index f1599c2..0000000
--- a/attrib/gatt.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2010  Nokia Corporation
- *  Copyright (C) 2010  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  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
- *
- */
-
-#define GATT_CID 4
-
-guint gatt_discover_primary(GAttrib *attrib, uint16_t start,
-		uint16_t end, GAttribResultFunc func, gpointer user_data);
-
-guint gatt_discover_char(GAttrib *attrib, uint16_t start, uint16_t end,
-				GAttribResultFunc func, gpointer user_data);
-
-guint gatt_read_char(GAttrib *attrib, uint16_t handle, GAttribResultFunc func,
-							gpointer user_data);
-
-guint gatt_write_char(GAttrib *attrib, uint16_t handle, uint8_t *value,
-			int vlen, GAttribResultFunc func, gpointer user_data);
-
-guint gatt_find_info(GAttrib *attrib, uint16_t start, uint16_t end,
-				GAttribResultFunc func, gpointer user_data);
-
-guint gatt_write_cmd(GAttrib *attrib, uint16_t handle, uint8_t *value, int vlen,
-				GDestroyNotify notify, gpointer user_data);
diff --git a/attrib/gattrib.c b/attrib/gattrib.c
deleted file mode 100644
index ed18168..0000000
--- a/attrib/gattrib.c
+++ /dev/null
@@ -1,535 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2010  Nokia Corporation
- *  Copyright (C) 2010  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  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
- *
- */
-
-#include <stdint.h>
-#include <string.h>
-#include <glib.h>
-
-#include <stdio.h>
-
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/sdp.h>
-
-#include "att.h"
-#include "gattrib.h"
-
-struct _GAttrib {
-	GIOChannel *io;
-	gint refs;
-	gint mtu;
-	guint read_watch;
-	guint write_watch;
-	GQueue *queue;
-	GSList *events;
-	guint next_cmd_id;
-	guint next_evt_id;
-	GDestroyNotify destroy;
-	GAttribDisconnectFunc disconnect;
-	gpointer destroy_user_data;
-	gpointer disc_user_data;
-};
-
-struct command {
-	guint id;
-	guint8 opcode;
-	guint8 *pdu;
-	guint16 len;
-	guint8 expected;
-	gboolean sent;
-	GAttribResultFunc func;
-	gpointer user_data;
-	GDestroyNotify notify;
-};
-
-struct event {
-	guint id;
-	guint8 expected;
-	GAttribNotifyFunc func;
-	gpointer user_data;
-	GDestroyNotify notify;
-};
-
-static guint8 opcode2expected(guint8 opcode)
-{
-	switch (opcode) {
-	case ATT_OP_MTU_REQ:
-		return ATT_OP_MTU_RESP;
-
-	case ATT_OP_FIND_INFO_REQ:
-		return ATT_OP_FIND_INFO_RESP;
-
-	case ATT_OP_FIND_BY_TYPE_REQ:
-		return ATT_OP_FIND_BY_TYPE_RESP;
-
-	case ATT_OP_READ_BY_TYPE_REQ:
-		return ATT_OP_READ_BY_TYPE_RESP;
-
-	case ATT_OP_READ_REQ:
-		return ATT_OP_READ_RESP;
-
-	case ATT_OP_READ_BLOB_REQ:
-		return ATT_OP_READ_BLOB_RESP;
-
-	case ATT_OP_READ_MULTI_REQ:
-		return ATT_OP_READ_MULTI_RESP;
-
-	case ATT_OP_READ_BY_GROUP_REQ:
-		return ATT_OP_READ_BY_GROUP_RESP;
-
-	case ATT_OP_WRITE_REQ:
-		return ATT_OP_WRITE_RESP;
-
-	case ATT_OP_PREP_WRITE_REQ:
-		return ATT_OP_PREP_WRITE_RESP;
-
-	case ATT_OP_EXEC_WRITE_REQ:
-		return ATT_OP_EXEC_WRITE_RESP;
-
-	case ATT_OP_HANDLE_IND:
-		return ATT_OP_HANDLE_CNF;
-	}
-
-	return 0;
-}
-
-static gboolean is_response(guint8 opcode)
-{
-	switch (opcode) {
-	case ATT_OP_ERROR:
-	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:
-		return TRUE;
-	}
-
-	return FALSE;
-}
-
-GAttrib *g_attrib_ref(GAttrib *attrib)
-{
-	if (!attrib)
-		return NULL;
-
-	g_atomic_int_inc(&attrib->refs);
-
-	return attrib;
-}
-
-static void command_destroy(struct command *cmd)
-{
-	if (cmd->notify)
-		cmd->notify(cmd->user_data);
-
-	g_free(cmd->pdu);
-	g_free(cmd);
-}
-
-static void event_destroy(struct event *evt)
-{
-	if (evt->notify)
-		evt->notify(evt->user_data);
-
-	g_free(evt);
-}
-
-void g_attrib_unref(GAttrib *attrib)
-{
-	GSList *l;
-	struct command *c;
-
-	if (!attrib)
-		return;
-
-	if (g_atomic_int_dec_and_test(&attrib->refs) == FALSE)
-		return;
-
-	while ((c = g_queue_pop_head(attrib->queue)))
-		command_destroy(c);
-
-	attrib->queue = NULL;
-
-	for (l = attrib->events; l; l = l->next)
-		event_destroy(l->data);
-
-	g_slist_free(attrib->events);
-	attrib->events = NULL;
-
-	if (attrib->write_watch > 0)
-		g_source_remove(attrib->write_watch);
-
-	if (attrib->read_watch > 0) {
-		g_source_remove(attrib->read_watch);
-		g_io_channel_unref(attrib->io);
-	}
-
-
-	if (attrib->destroy)
-		attrib->destroy(attrib->destroy_user_data);
-
-	g_free(attrib);
-}
-
-gboolean g_attrib_set_disconnect_function(GAttrib *attrib,
-		GAttribDisconnectFunc disconnect, gpointer user_data)
-{
-	if (attrib == NULL)
-		return FALSE;
-
-	attrib->disconnect = disconnect;
-	attrib->disc_user_data = user_data;
-
-	return TRUE;
-}
-
-gboolean g_attrib_set_destroy_function(GAttrib *attrib,
-		GDestroyNotify destroy, gpointer user_data)
-{
-	if (attrib == NULL)
-		return FALSE;
-
-	attrib->destroy = destroy;
-	attrib->destroy_user_data = user_data;
-
-	return TRUE;
-}
-
-static gboolean can_write_data(GIOChannel *io, GIOCondition cond,
-								gpointer data)
-{
-	struct _GAttrib *attrib = data;
-	struct command *cmd;
-	GError *gerr = NULL;
-	gsize len;
-	GIOStatus iostat;
-
-	if (cond & (G_IO_HUP | G_IO_ERR | G_IO_NVAL)) {
-		if (attrib->disconnect)
-			attrib->disconnect(attrib->disc_user_data);
-
-		return FALSE;
-	}
-
-	cmd = g_queue_peek_head(attrib->queue);
-	if (cmd == NULL)
-		return FALSE;
-
-	iostat = g_io_channel_write_chars(io, (gchar *) cmd->pdu, cmd->len,
-								&len, &gerr);
-	if (iostat != G_IO_STATUS_NORMAL)
-		return FALSE;
-
-	g_io_channel_flush(io, NULL);
-
-	if (cmd->expected == 0) {
-		g_queue_pop_head(attrib->queue);
-		command_destroy(cmd);
-
-		return TRUE;
-	}
-
-	cmd->sent = TRUE;
-
-	return FALSE;
-}
-
-static void destroy_sender(gpointer data)
-{
-	struct _GAttrib *attrib = data;
-
-	attrib->write_watch = 0;
-}
-
-static void wake_up_sender(struct _GAttrib *attrib)
-{
-	if (attrib->write_watch == 0)
-		attrib->write_watch = g_io_add_watch_full(attrib->io,
-			G_PRIORITY_DEFAULT, G_IO_OUT, can_write_data,
-			attrib, destroy_sender);
-}
-
-static gboolean received_data(GIOChannel *io, GIOCondition cond, gpointer data)
-{
-	struct _GAttrib *attrib = data;
-	struct command *cmd = NULL;
-	GSList *l;
-	uint8_t buf[512], status;
-	gsize len;
-	GIOStatus iostat;
-
-	if (cond & (G_IO_HUP | G_IO_ERR | G_IO_NVAL)) {
-		attrib->read_watch = 0;
-		if (attrib->disconnect)
-			attrib->disconnect(attrib->disc_user_data);
-		return FALSE;
-	}
-
-	memset(buf, 0, sizeof(buf));
-
-	iostat = g_io_channel_read_chars(io, (gchar *) buf, sizeof(buf),
-								&len, NULL);
-	if (iostat != G_IO_STATUS_NORMAL) {
-		status = ATT_ECODE_IO;
-		goto done;
-	}
-
-	for (l = attrib->events; l; l = l->next) {
-		struct event *evt = l->data;
-
-		if (evt->expected == buf[0] ||
-					evt->expected == GATTRIB_ALL_EVENTS)
-			evt->func(buf, len, evt->user_data);
-	}
-
-	if (is_response(buf[0]) == FALSE)
-		return TRUE;
-
-	cmd = g_queue_pop_head(attrib->queue);
-	if (cmd == NULL) {
-		/* Keep the watch if we have events to report */
-		return attrib->events != NULL;
-	}
-
-	if (buf[0] == ATT_OP_ERROR) {
-		status = buf[4];
-		goto done;
-	}
-
-	if (cmd->expected != buf[0]) {
-		status = ATT_ECODE_IO;
-		goto done;
-	}
-
-	status = 0;
-
-done:
-	if (attrib->queue && g_queue_is_empty(attrib->queue) == FALSE)
-		wake_up_sender(attrib);
-
-	if (cmd) {
-		if (cmd->func)
-			cmd->func(status, buf, len, cmd->user_data);
-
-		command_destroy(cmd);
-	}
-
-	return TRUE;
-}
-
-GAttrib *g_attrib_new(GIOChannel *io)
-{
-	struct _GAttrib *attrib;
-
-	g_io_channel_set_encoding(io, NULL, NULL);
-
-	attrib = g_try_new0(struct _GAttrib, 1);
-	if (attrib == NULL)
-		return NULL;
-
-	attrib->io = g_io_channel_ref(io);
-	attrib->mtu = 512;
-	attrib->queue = g_queue_new();
-
-	attrib->read_watch = g_io_add_watch(attrib->io,
-			G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
-			received_data, attrib);
-
-	return g_attrib_ref(attrib);
-}
-
-guint g_attrib_send(GAttrib *attrib, guint8 opcode, const guint8 *pdu,
-				guint16 len, GAttribResultFunc func,
-				gpointer user_data, GDestroyNotify notify)
-{
-	struct command *c;
-
-	c = g_try_new0(struct command, 1);
-	if (c == NULL)
-		return 0;
-
-	c->opcode = opcode;
-	c->expected = opcode2expected(opcode);
-	c->pdu = g_malloc(len);
-	memcpy(c->pdu, pdu, len);
-	c->len = len;
-	c->func = func;
-	c->user_data = user_data;
-	c->notify = notify;
-	c->id = ++attrib->next_cmd_id;
-
-	g_queue_push_tail(attrib->queue, c);
-
-	if (g_queue_get_length(attrib->queue) == 1)
-		wake_up_sender(attrib);
-
-	return c->id;
-}
-
-static gint command_cmp_by_id(gconstpointer a, gconstpointer b)
-{
-	const struct command *cmd = a;
-	guint id = GPOINTER_TO_UINT(b);
-
-	return cmd->id - id;
-}
-
-gboolean g_attrib_cancel(GAttrib *attrib, guint id)
-{
-	GList *l;
-	struct command *cmd;
-
-	if (attrib == NULL || attrib->queue == NULL)
-		return FALSE;
-
-	l = g_queue_find_custom(attrib->queue, GUINT_TO_POINTER(id),
-							command_cmp_by_id);
-	if (l == NULL)
-		return FALSE;
-
-	cmd = l->data;
-
-	if (cmd == g_queue_peek_head(attrib->queue) && cmd->sent)
-		cmd->func = NULL;
-	else {
-		g_queue_remove(attrib->queue, cmd);
-		command_destroy(cmd);
-	}
-
-	return TRUE;
-}
-
-gboolean g_attrib_cancel_all(GAttrib *attrib)
-{
-	struct command *c, *head = NULL;
-	gboolean first = TRUE;
-
-	if (attrib == NULL || attrib->queue == NULL)
-		return FALSE;
-
-	while ((c = g_queue_pop_head(attrib->queue))) {
-		if (first && c->sent) {
-			/* If the command was sent ignore its callback ... */
-			c->func = NULL;
-			head = c;
-			continue;
-		}
-
-		first = FALSE;
-		command_destroy(c);
-	}
-
-	if (head) {
-		/* ... and put it back in the queue */
-		g_queue_push_head(attrib->queue, head);
-	}
-
-	return TRUE;
-}
-
-gboolean g_attrib_set_debug(GAttrib *attrib,
-		GAttribDebugFunc func, gpointer user_data)
-{
-	return TRUE;
-}
-
-guint g_attrib_register(GAttrib *attrib, guint8 opcode,
-				GAttribNotifyFunc func, gpointer user_data,
-				GDestroyNotify notify)
-{
-	struct event *event;
-
-	event = g_try_new0(struct event, 1);
-	if (event == NULL)
-		return 0;
-
-	event->expected = opcode;
-	event->func = func;
-	event->user_data = user_data;
-	event->notify = notify;
-	event->id = ++attrib->next_evt_id;
-
-	attrib->events = g_slist_append(attrib->events, event);
-
-	return event->id;
-}
-
-static gint event_cmp_by_id(gconstpointer a, gconstpointer b)
-{
-	const struct event *evt = a;
-	guint id = GPOINTER_TO_UINT(b);
-
-	return evt->id - id;
-}
-
-gboolean g_attrib_unregister(GAttrib *attrib, guint id)
-{
-	struct event *evt;
-	GSList *l;
-
-	l = g_slist_find_custom(attrib->events, GUINT_TO_POINTER(id),
-							event_cmp_by_id);
-	if (l == NULL)
-		return FALSE;
-
-	evt = l->data;
-
-	attrib->events = g_slist_remove(attrib->events, evt);
-
-	if (evt->notify)
-		evt->notify(evt->user_data);
-
-	g_free(evt);
-
-	return TRUE;
-}
-
-gboolean g_attrib_unregister_all(GAttrib *attrib)
-{
-	GSList *l;
-
-	if (attrib->events == NULL)
-		return FALSE;
-
-	for (l = attrib->events; l; l = l->next) {
-		struct event *evt = l->data;
-
-		if (evt->notify)
-			evt->notify(evt->user_data);
-
-		g_free(evt);
-	}
-
-	g_slist_free(attrib->events);
-	attrib->events = NULL;
-
-	return TRUE;
-}
diff --git a/attrib/gattrib.h b/attrib/gattrib.h
deleted file mode 100644
index 4306ca4..0000000
--- a/attrib/gattrib.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2010  Nokia Corporation
- *  Copyright (C) 2010  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  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
- *
- */
-#ifndef __GATTRIB_H
-#define __GATTRIB_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define GATTRIB_ALL_EVENTS 0xFF
-
-struct _GAttrib;
-typedef struct _GAttrib GAttrib;
-
-typedef void (*GAttribResultFunc) (guint8 status, const guint8 *pdu,
-					guint16 len, gpointer user_data);
-typedef void (*GAttribDisconnectFunc)(gpointer user_data);
-typedef void (*GAttribDebugFunc)(const char *str, gpointer user_data);
-typedef void (*GAttribNotifyFunc)(const guint8 *pdu, guint16 len,
-							gpointer user_data);
-
-GAttrib *g_attrib_new(GIOChannel *io);
-GAttrib *g_attrib_ref(GAttrib *attrib);
-void g_attrib_unref(GAttrib *attrib);
-
-gboolean g_attrib_set_disconnect_function(GAttrib *attrib,
-		GAttribDisconnectFunc disconnect, gpointer user_data);
-
-gboolean g_attrib_set_destroy_function(GAttrib *attrib,
-		GDestroyNotify destroy, gpointer user_data);
-
-guint g_attrib_send(GAttrib *attrib, guint8 opcode, const guint8 *pdu,
-				guint16 len, GAttribResultFunc func,
-				gpointer user_data, GDestroyNotify notify);
-gboolean g_attrib_cancel(GAttrib *attrib, guint id);
-gboolean g_attrib_cancel_all(GAttrib *attrib);
-
-gboolean g_attrib_set_debug(GAttrib *attrib,
-		GAttribDebugFunc func, gpointer user_data);
-
-guint g_attrib_register(GAttrib *attrib, guint8 opcode,
-		GAttribNotifyFunc func, gpointer user_data,
-					GDestroyNotify notify);
-
-gboolean g_attrib_unregister(GAttrib *attrib, guint id);
-gboolean g_attrib_unregister_all(GAttrib *attrib);
-
-#ifdef __cplusplus
-}
-#endif
-#endif
diff --git a/src/att.c b/src/att.c
new file mode 100644
index 0000000..fe41d0e
--- /dev/null
+++ b/src/att.c
@@ -0,0 +1,764 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2010  Nokia Corporation
+ *  Copyright (C) 2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  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
+ *
+ */
+
+#include <errno.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/sdp.h>
+#include <bluetooth/sdp_lib.h>
+
+#include "att.h"
+
+const char *att_ecode2str(uint8_t status)
+{
+	switch (status)  {
+	case ATT_ECODE_INVALID_HANDLE:
+		return "Invalid handle";
+	case ATT_ECODE_READ_NOT_PERM:
+		return "Atribute can't be read";
+	case ATT_ECODE_WRITE_NOT_PERM:
+		return "Attribute can't be written";
+	case ATT_ECODE_INVALID_PDU:
+		return "Attribute PDU was invalid";
+	case ATT_ECODE_INSUFF_AUTHEN:
+		return "Attribute requires authentication before read/write";
+	case ATT_ECODE_REQ_NOT_SUPP:
+		return "Server doesn't support the request received";
+	case ATT_ECODE_INVALID_OFFSET:
+		return "Offset past the end of the attribute";
+	case ATT_ECODE_INSUFF_AUTHO:
+		return "Attribute requires authorization before read/write";
+	case ATT_ECODE_PREP_QUEUE_FULL:
+		return "Too many prepare writes have been queued";
+	case ATT_ECODE_ATTR_NOT_FOUND:
+		return "No attribute found within the given range";
+	case ATT_ECODE_ATTR_NOT_LONG:
+		return "Attribute can't be read/written using Read Blob Req";
+	case ATT_ECODE_INSUFF_ENCR_KEY_SIZE:
+		return "Encryption Key Size is insufficient";
+	case ATT_ECODE_INVAL_ATTR_VALUE_LEN:
+		return "Attribute value length is invalid";
+	case ATT_ECODE_UNLIKELY:
+		return "Request attribute has encountered an unlikely error";
+	case ATT_ECODE_INSUFF_ENC:
+		return "Encryption required before read/write";
+	case ATT_ECODE_UNSUPP_GRP_TYPE:
+		return "Attribute type is not a supported grouping attribute";
+	case ATT_ECODE_INSUFF_RESOURCES:
+		return "Insufficient Resources to complete the request";
+	case ATT_ECODE_IO:
+		return "Internal application error: I/O";
+	default:
+		return "Unexpected error code";
+	}
+}
+
+void att_data_list_free(struct att_data_list *list)
+{
+	int i;
+
+	for (i = 0; i < list->num; i++)
+		free(list->data[i]);
+
+	free(list->data);
+	free(list);
+}
+
+uint16_t enc_read_by_grp_req(uint16_t start, uint16_t end, uuid_t *uuid,
+							uint8_t *pdu, int len)
+{
+	const uint16_t min_len = sizeof(pdu[0]) + sizeof(start) + sizeof(end);
+	uint16_t length;
+
+	if (!uuid)
+		return 0;
+
+	if (uuid->type == SDP_UUID16)
+		length = 2;
+	else if (uuid->type == SDP_UUID128)
+		length = 16;
+	else
+		return 0;
+
+	if (len < min_len + length)
+		return 0;
+
+	pdu[0] = ATT_OP_READ_BY_GROUP_REQ;
+	att_put_u16(start, &pdu[1]);
+	att_put_u16(end, &pdu[3]);
+
+	if (uuid->type == SDP_UUID16)
+		att_put_u16(uuid->value.uuid16, &pdu[5]);
+	else
+		memcpy(&pdu[5], &uuid->value.uuid128, length);
+
+	return min_len + length;
+}
+
+uint16_t dec_read_by_grp_req(const uint8_t *pdu, int len, uint16_t *start,
+						uint16_t *end, uuid_t *uuid)
+{
+	const uint16_t min_len = sizeof(pdu[0]) + sizeof(*start) + sizeof(*end);
+
+	if (pdu == NULL)
+		return 0;
+
+	if (start == NULL || end == NULL || uuid == NULL)
+		return 0;
+
+	if (pdu[0] != ATT_OP_READ_BY_GROUP_REQ)
+		return 0;
+
+	if (len < min_len + 2)
+		return 0;
+
+	*start = att_get_u16(&pdu[1]);
+	*end = att_get_u16(&pdu[3]);
+	if (len == min_len + 2)
+		sdp_uuid16_create(uuid, att_get_u16(&pdu[5]));
+	else
+		sdp_uuid128_create(uuid, &pdu[5]);
+
+	return len;
+}
+
+uint16_t enc_read_by_grp_resp(struct att_data_list *list, uint8_t *pdu,
+								int len)
+{
+	int i;
+	uint16_t w;
+	uint8_t *ptr;
+
+	if (list == NULL)
+		return 0;
+
+	if (len < list->len + 2)
+		return 0;
+
+	pdu[0] = ATT_OP_READ_BY_GROUP_RESP;
+	pdu[1] = list->len;
+
+	ptr = &pdu[2];
+
+	for (i = 0, w = 2; i < list->num && w + list->len <= len; i++) {
+		memcpy(ptr, list->data[i], list->len);
+		ptr += list->len;
+		w += list->len;
+	}
+
+	return w;
+}
+
+struct att_data_list *dec_read_by_grp_resp(const uint8_t *pdu, int len)
+{
+	struct att_data_list *list;
+	const uint8_t *ptr;
+	int i;
+
+	if (pdu[0] != ATT_OP_READ_BY_GROUP_RESP)
+		return NULL;
+
+	list = malloc(sizeof(struct att_data_list));
+	list->len = pdu[1];
+	list->num = (len - 2) / list->len;
+
+	list->data = malloc(sizeof(uint8_t *) * list->num);
+	ptr = &pdu[2];
+
+	for (i = 0; i < list->num; i++) {
+		list->data[i] = malloc(sizeof(uint8_t) * list->len);
+		memcpy(list->data[i], ptr, list->len);
+		ptr += list->len;
+	}
+
+	return list;
+}
+
+uint16_t enc_find_by_type_req(uint16_t start, uint16_t end, uuid_t *uuid,
+							uint8_t *pdu, int len)
+{
+	return 0;
+}
+
+uint16_t enc_read_by_type_req(uint16_t start, uint16_t end, uuid_t *uuid,
+							uint8_t *pdu, int len)
+{
+	const uint16_t min_len = sizeof(pdu[0]) + sizeof(start) + sizeof(end);
+	uint16_t length;
+
+	if (!uuid)
+		return 0;
+
+	if (uuid->type == SDP_UUID16)
+		length = 2;
+	else if (uuid->type == SDP_UUID128)
+		length = 16;
+	else
+		return 0;
+
+	if (len < min_len + length)
+		return 0;
+
+	pdu[0] = ATT_OP_READ_BY_TYPE_REQ;
+	att_put_u16(start, &pdu[1]);
+	att_put_u16(end, &pdu[3]);
+
+	if (uuid->type == SDP_UUID16)
+		att_put_u16(uuid->value.uuid16, &pdu[5]);
+	else
+		memcpy(&pdu[5], &uuid->value.uuid128, length);
+
+	return min_len + length;
+}
+
+uint16_t dec_read_by_type_req(const uint8_t *pdu, int len, uint16_t *start,
+						uint16_t *end, uuid_t *uuid)
+{
+	const uint16_t min_len = sizeof(pdu[0]) + sizeof(*start) + sizeof(*end);
+
+	if (pdu == NULL)
+		return 0;
+
+	if (start == NULL || end == NULL || uuid == NULL)
+		return 0;
+
+	if (len < min_len + 2)
+		return 0;
+
+	if (pdu[0] != ATT_OP_READ_BY_TYPE_REQ)
+		return 0;
+
+	*start = att_get_u16(&pdu[1]);
+	*end = att_get_u16(&pdu[3]);
+
+	if (len == min_len + 2)
+		sdp_uuid16_create(uuid, att_get_u16(&pdu[5]));
+	else
+		sdp_uuid128_create(uuid, &pdu[5]);
+
+	return len;
+}
+
+uint16_t enc_read_by_type_resp(struct att_data_list *list, uint8_t *pdu, int len)
+{
+	uint8_t *ptr;
+	int i, w;
+
+	if (list == NULL)
+		return 0;
+
+	if (pdu == NULL)
+		return 0;
+
+	if (len < list->len + 2)
+		return 0;
+
+	pdu[0] = ATT_OP_READ_BY_TYPE_RESP;
+	pdu[1] = list->len;
+	ptr = &pdu[2];
+
+	for (i = 0, w = 2; i < list->num && w + list->len <= len; i++) {
+		memcpy(ptr, list->data[i], list->len);
+		ptr += list->len;
+		w += list->len;
+	}
+
+	return w;
+}
+
+struct att_data_list *dec_read_by_type_resp(const uint8_t *pdu, int len)
+{
+	struct att_data_list *list;
+	const uint8_t *ptr;
+	int i;
+
+	if (pdu[0] != ATT_OP_READ_BY_TYPE_RESP)
+		return NULL;
+
+	list = malloc(sizeof(struct att_data_list));
+	list->len = pdu[1];
+	list->num = (len - 2) / list->len;
+
+	list->data = malloc(sizeof(uint8_t *) * list->num);
+	ptr = &pdu[2];
+
+	for (i = 0; i < list->num; i++) {
+		list->data[i] = malloc(sizeof(uint8_t) * list->len);
+		memcpy(list->data[i], ptr, list->len);
+		ptr += list->len;
+	}
+
+	return list;
+}
+
+uint16_t enc_write_cmd(uint16_t handle, const uint8_t *value, int vlen,
+							uint8_t *pdu, int len)
+{
+	const uint16_t min_len = sizeof(pdu[0]) + sizeof(handle);
+
+	if (pdu == NULL)
+		return 0;
+
+	if (len < min_len)
+		return 0;
+
+	if (vlen > len - min_len)
+		vlen = len - min_len;
+
+	pdu[0] = ATT_OP_WRITE_CMD;
+	att_put_u16(handle, &pdu[1]);
+
+	if (vlen > 0) {
+		memcpy(&pdu[3], value, vlen);
+		return min_len + vlen;
+	}
+
+	return min_len;
+}
+
+uint16_t dec_write_cmd(const uint8_t *pdu, int len, uint16_t *handle,
+						uint8_t *value, int *vlen)
+{
+	const uint16_t min_len = sizeof(pdu[0]) + sizeof(*handle);
+
+	if (pdu == NULL)
+		return 0;
+
+	if (value == NULL || vlen == NULL || handle == NULL)
+		return 0;
+
+	if (len < min_len)
+		return 0;
+
+	if (pdu[0] != ATT_OP_WRITE_CMD)
+		return 0;
+
+	*handle = att_get_u16(&pdu[1]);
+	memcpy(value, pdu + min_len, len - min_len);
+	*vlen = len - min_len;
+
+	return len;
+}
+
+uint16_t enc_write_req(uint16_t handle, const uint8_t *value, int vlen,
+							uint8_t *pdu, int len)
+{
+	const uint16_t min_len = sizeof(pdu[0]) + sizeof(handle);
+
+	if (pdu == NULL)
+		return 0;
+
+	if (len < min_len)
+		return 0;
+
+	if (vlen > len - min_len)
+		vlen = len - min_len;
+
+	pdu[0] = ATT_OP_WRITE_REQ;
+	att_put_u16(handle, &pdu[1]);
+
+	if (vlen > 0) {
+		memcpy(&pdu[3], value, vlen);
+		return min_len + vlen;
+	}
+
+	return min_len;
+}
+
+uint16_t dec_write_req(const uint8_t *pdu, int len, uint16_t *handle,
+						uint8_t *value, int *vlen)
+{
+	const uint16_t min_len = sizeof(pdu[0]) + sizeof(*handle);
+
+	if (pdu == NULL)
+		return 0;
+
+	if (value == NULL || vlen == NULL || handle == NULL)
+		return 0;
+
+	if (len < min_len)
+		return 0;
+
+	if (pdu[0] != ATT_OP_WRITE_REQ)
+		return 0;
+
+	*handle = att_get_u16(&pdu[1]);
+	*vlen = len - min_len;
+	if (*vlen > 0)
+		memcpy(value, pdu + min_len, *vlen);
+
+	return len;
+}
+
+uint16_t enc_read_req(uint16_t handle, uint8_t *pdu, int len)
+{
+	const uint16_t min_len = sizeof(pdu[0]) + sizeof(handle);
+
+	if (pdu == NULL)
+		return 0;
+
+	if (len < min_len)
+		return 0;
+
+	pdu[0] = ATT_OP_READ_REQ;
+	att_put_u16(handle, &pdu[1]);
+
+	return min_len;
+}
+
+uint16_t dec_read_req(const uint8_t *pdu, int len, uint16_t *handle)
+{
+	const uint16_t min_len = sizeof(pdu[0]) + sizeof(*handle);
+
+	if (pdu == NULL)
+		return 0;
+
+	if (handle == NULL)
+		return 0;
+
+	if (len < min_len)
+		return 0;
+
+	if (pdu[0] != ATT_OP_READ_REQ)
+		return 0;
+
+	*handle = att_get_u16(&pdu[1]);
+
+	return min_len;
+}
+
+uint16_t enc_read_resp(uint8_t *value, int vlen, uint8_t *pdu, int len)
+{
+	if (pdu == NULL)
+		return 0;
+
+	/* If the attribute value length is longer than the allowed PDU size,
+	 * send only the octets that fit on the PDU. The remaining octets can
+	 * be requested using the Read Blob Request. */
+	if (vlen > len - 1)
+		vlen = len - 1;
+
+	pdu[0] = ATT_OP_READ_RESP;
+
+	memcpy(pdu + 1, value, vlen);
+
+	return vlen + 1;
+}
+
+uint16_t dec_read_resp(const uint8_t *pdu, int len, uint8_t *value, int *vlen)
+{
+	if (pdu == NULL)
+		return 0;
+
+	if (value == NULL || vlen == NULL)
+		return 0;
+
+	if (pdu[0] != ATT_OP_READ_RESP)
+		return 0;
+
+	memcpy(value, pdu + 1, len - 1);
+
+	*vlen = len - 1;
+
+	return len;
+}
+
+uint16_t enc_error_resp(uint8_t opcode, uint16_t handle, uint8_t status,
+							uint8_t *pdu, int len)
+{
+	const uint16_t min_len = sizeof(pdu[0]) + sizeof(opcode) +
+						sizeof(handle) + sizeof(status);
+	uint16_t u16;
+
+	if (len < min_len)
+		return 0;
+
+	u16 = htobs(handle);
+	pdu[0] = ATT_OP_ERROR;
+	pdu[1] = opcode;
+	memcpy(&pdu[2], &u16, sizeof(u16));
+	pdu[4] = status;
+
+	return min_len;
+}
+
+uint16_t enc_find_info_req(uint16_t start, uint16_t end, uint8_t *pdu, int len)
+{
+	const uint16_t min_len = sizeof(pdu[0]) + sizeof(start) + sizeof(end);
+
+	if (pdu == NULL)
+		return 0;
+
+	if (len < min_len)
+		return 0;
+
+	pdu[0] = ATT_OP_FIND_INFO_REQ;
+	att_put_u16(start, &pdu[1]);
+	att_put_u16(end, &pdu[3]);
+
+	return min_len;
+}
+
+uint16_t dec_find_info_req(const uint8_t *pdu, int len, uint16_t *start,
+								uint16_t *end)
+{
+	const uint16_t min_len = sizeof(pdu[0]) + sizeof(*start) + sizeof(*end);
+
+	if (pdu == NULL)
+		return 0;
+
+	if (len < min_len)
+		return 0;
+
+	if (start == NULL || end == NULL)
+		return 0;
+
+	if (pdu[0] != ATT_OP_FIND_INFO_REQ)
+		return 0;
+
+	*start = att_get_u16(&pdu[1]);
+	*end = att_get_u16(&pdu[3]);
+
+	return min_len;
+}
+
+uint16_t enc_find_info_resp(uint8_t format, struct att_data_list *list,
+							uint8_t *pdu, int len)
+{
+	uint8_t *ptr;
+	int i, w;
+
+	if (pdu == NULL)
+		return 0;
+
+	if (list == NULL)
+		return 0;
+
+	if (len < list->len + 2)
+		return 0;
+
+	pdu[0] = ATT_OP_FIND_INFO_RESP;
+	pdu[1] = format;
+	ptr = (void *) &pdu[2];
+
+	for (i = 0, w = 2; i < list->num && w + list->len <= len; i++) {
+		memcpy(ptr, list->data[i], list->len);
+		ptr += list->len;
+		w += list->len;
+	}
+
+	return w;
+}
+
+struct att_data_list *dec_find_info_resp(const uint8_t *pdu, int len,
+							uint8_t *format)
+{
+	struct att_data_list *list;
+	uint8_t *ptr;
+	int i;
+
+	if (pdu == NULL)
+		return 0;
+
+	if (format == NULL)
+		return 0;
+
+	if (pdu[0] != ATT_OP_FIND_INFO_RESP)
+		return 0;
+
+	*format = pdu[1];
+
+	list = malloc(sizeof(struct att_data_list));
+
+	list->len = sizeof(pdu[0]) + sizeof(*format);
+	if (*format == 0x01)
+		list->len += 2;
+	else if (*format == 0x02)
+		list->len += 16;
+
+	list->num = (len - 2) / list->len;
+	list->data = malloc(sizeof(uint8_t *) * list->num);
+
+	ptr = (void *) &pdu[2];
+
+	for (i = 0; i < list->num; i++) {
+		list->data[i] = malloc(list->len);
+		memcpy(list->data[i], ptr, list->len);
+		ptr += list->len;
+	}
+
+	return list;
+}
+
+uint16_t enc_notification(struct attribute *a, uint8_t *pdu, int len)
+{
+	const uint16_t min_len = sizeof(pdu[0]) + sizeof(uint16_t);
+
+	if (pdu == NULL)
+		return 0;
+
+	if (len < (a->len + min_len))
+		return 0;
+
+	pdu[0] = ATT_OP_HANDLE_NOTIFY;
+	att_put_u16(a->handle, &pdu[1]);
+	memcpy(&pdu[3], a->data, a->len);
+
+	return a->len + min_len;
+}
+
+uint16_t enc_indication(struct attribute *a, uint8_t *pdu, int len)
+{
+	const uint16_t min_len = sizeof(pdu[0]) + sizeof(uint16_t);
+
+	if (pdu == NULL)
+		return 0;
+
+	if (len < (a->len + min_len))
+		return 0;
+
+	pdu[0] = ATT_OP_HANDLE_IND;
+	att_put_u16(a->handle, &pdu[1]);
+	memcpy(&pdu[3], a->data, a->len);
+
+	return a->len + min_len;
+}
+
+struct attribute *dec_indication(const uint8_t *pdu, int len)
+{
+	const uint16_t min_len = sizeof(pdu[0]) + sizeof(uint16_t);
+
+	struct attribute *a;
+
+	if (pdu == NULL)
+		return NULL;
+
+	if (pdu[0] != ATT_OP_HANDLE_IND)
+		return NULL;
+
+	if (len < min_len)
+		return NULL;
+
+	a = malloc(sizeof(struct attribute) + len - min_len);
+	if (a == NULL)
+		return NULL;
+
+	a->len = len - min_len;
+
+	a->handle = att_get_u16(&pdu[1]);
+	memcpy(a->data, &pdu[3], a->len);
+
+	return a;
+}
+
+uint16_t enc_confirmation(uint8_t *pdu, int len)
+{
+	const uint16_t min_len = sizeof(pdu[0]);
+
+	if (pdu == NULL)
+		return 0;
+
+	if (len < min_len)
+		return 0;
+
+	pdu[0] = ATT_OP_HANDLE_CNF;
+
+	return min_len;
+}
+
+uint16_t enc_mtu_req(uint16_t mtu, uint8_t *pdu, int len)
+{
+	const uint16_t min_len = sizeof(pdu[0]) + sizeof(mtu);
+
+	if (pdu == NULL)
+		return 0;
+
+	if (len < min_len)
+		return 0;
+
+	pdu[0] = ATT_OP_MTU_REQ;
+	att_put_u16(mtu, &pdu[1]);
+
+	return min_len;
+}
+
+uint16_t dec_mtu_req(const uint8_t *pdu, int len, uint16_t *mtu)
+{
+	const uint16_t min_len = sizeof(pdu[0]) + sizeof(*mtu);
+
+	if (pdu == NULL)
+		return 0;
+
+	if (mtu == NULL)
+		return 0;
+
+	if (len < min_len)
+		return 0;
+
+	if (pdu[0] != ATT_OP_MTU_REQ)
+		return 0;
+
+	*mtu = att_get_u16(&pdu[1]);
+
+	return min_len;
+}
+
+uint16_t enc_mtu_resp(uint16_t mtu, uint8_t *pdu, int len)
+{
+	const uint16_t min_len = sizeof(pdu[0]) + sizeof(mtu);
+
+	if (pdu == NULL)
+		return 0;
+
+	if (len < min_len)
+		return 0;
+
+	pdu[0] = ATT_OP_MTU_RESP;
+	att_put_u16(mtu, &pdu[1]);
+
+	return min_len;
+}
+
+uint16_t dec_mtu_resp(const uint8_t *pdu, int len, uint16_t *mtu)
+{
+	const uint16_t min_len = sizeof(pdu[0]) + sizeof(*mtu);
+
+	if (pdu == NULL)
+		return 0;
+
+	if (mtu == NULL)
+		return 0;
+
+	if (len < min_len)
+		return 0;
+
+	if (pdu[0] != ATT_OP_MTU_RESP)
+		return 0;
+
+	*mtu = att_get_u16(&pdu[1]);
+
+	return min_len;
+}
diff --git a/src/att.h b/src/att.h
new file mode 100644
index 0000000..ea49dc2
--- /dev/null
+++ b/src/att.h
@@ -0,0 +1,206 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2010  Nokia Corporation
+ *  Copyright (C) 2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  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
+ *
+ */
+
+/* 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
+
+/* Attribute Protocol Opcodes */
+#define ATT_OP_ERROR			0x01
+#define ATT_OP_MTU_REQ			0x02
+#define ATT_OP_MTU_RESP			0x03
+#define ATT_OP_FIND_INFO_REQ		0x04
+#define ATT_OP_FIND_INFO_RESP		0x05
+#define ATT_OP_FIND_BY_TYPE_REQ		0x06
+#define ATT_OP_FIND_BY_TYPE_RESP	0x07
+#define ATT_OP_READ_BY_TYPE_REQ		0x08
+#define ATT_OP_READ_BY_TYPE_RESP	0x09
+#define ATT_OP_READ_REQ			0x0A
+#define ATT_OP_READ_RESP		0x0B
+#define ATT_OP_READ_BLOB_REQ		0x0C
+#define ATT_OP_READ_BLOB_RESP		0x0D
+#define ATT_OP_READ_MULTI_REQ		0x0E
+#define ATT_OP_READ_MULTI_RESP		0x0F
+#define ATT_OP_READ_BY_GROUP_REQ	0x10
+#define ATT_OP_READ_BY_GROUP_RESP	0x11
+#define ATT_OP_WRITE_REQ		0x12
+#define ATT_OP_WRITE_RESP		0x13
+#define ATT_OP_WRITE_CMD		0x52
+#define ATT_OP_PREP_WRITE_REQ		0x16
+#define ATT_OP_PREP_WRITE_RESP		0x17
+#define ATT_OP_EXEC_WRITE_REQ		0x18
+#define ATT_OP_EXEC_WRITE_RESP		0x19
+#define ATT_OP_HANDLE_NOTIFY		0x1B
+#define ATT_OP_HANDLE_IND		0x1D
+#define ATT_OP_HANDLE_CNF		0x1E
+#define ATT_OP_SIGNED_WRITE_CMD		0xD2
+
+/* Error codes for Error response PDU */
+#define ATT_ECODE_INVALID_HANDLE		0x01
+#define ATT_ECODE_READ_NOT_PERM			0x02
+#define ATT_ECODE_WRITE_NOT_PERM		0x03
+#define ATT_ECODE_INVALID_PDU			0x04
+#define ATT_ECODE_INSUFF_AUTHEN			0x05
+#define ATT_ECODE_REQ_NOT_SUPP			0x06
+#define ATT_ECODE_INVALID_OFFSET		0x07
+#define ATT_ECODE_INSUFF_AUTHO			0x08
+#define ATT_ECODE_PREP_QUEUE_FULL		0x09
+#define ATT_ECODE_ATTR_NOT_FOUND		0x0A
+#define ATT_ECODE_ATTR_NOT_LONG			0x0B
+#define ATT_ECODE_INSUFF_ENCR_KEY_SIZE		0x0C
+#define ATT_ECODE_INVAL_ATTR_VALUE_LEN		0x0D
+#define ATT_ECODE_UNLIKELY			0x0E
+#define ATT_ECODE_INSUFF_ENC			0x0F
+#define ATT_ECODE_UNSUPP_GRP_TYPE		0x10
+#define ATT_ECODE_INSUFF_RESOURCES		0x11
+/* Application error */
+#define ATT_ECODE_IO				0xFF
+
+/* Characteristic Property bit field */
+#define ATT_CHAR_PROPER_BROADCAST		0x01
+#define ATT_CHAR_PROPER_READ			0x02
+#define ATT_CHAR_PROPER_WRITE_WITHOUT_RESP	0x04
+#define ATT_CHAR_PROPER_WRITE			0x08
+#define ATT_CHAR_PROPER_NOTIFY			0x10
+#define ATT_CHAR_PROPER_INDICATE		0x20
+#define ATT_CHAR_PROPER_AUTH			0x40
+#define ATT_CHAR_PROPER_EXT_PROPER		0x80
+
+
+#define ATT_MAX_MTU				256
+#define ATT_DEFAULT_MTU				23
+
+struct attribute {
+	uint16_t handle;
+	uuid_t uuid;
+	int len;
+	uint8_t data[0];
+};
+
+struct att_data_list {
+	uint16_t num;
+	uint16_t len;
+	uint8_t **data;
+};
+
+/* These functions do byte conversion */
+static inline uint8_t att_get_u8(const void *ptr)
+{
+	const uint8_t *u8_ptr = ptr;
+	return bt_get_unaligned(u8_ptr);
+}
+
+static inline uint16_t att_get_u16(const void *ptr)
+{
+	const uint16_t *u16_ptr = ptr;
+	return btohs(bt_get_unaligned(u16_ptr));
+}
+
+static inline uint32_t att_get_u32(const void *ptr)
+{
+	const uint32_t *u32_ptr = ptr;
+	return btohl(bt_get_unaligned(u32_ptr));
+}
+
+static inline void att_put_u8(uint8_t src, void *dst)
+{
+	bt_put_unaligned(src, (uint8_t *) dst);
+}
+
+static inline void att_put_u16(uint16_t src, void *dst)
+{
+	bt_put_unaligned(htobs(src), (uint16_t *) dst);
+}
+
+static inline void att_put_u32(uint16_t src, void *dst)
+{
+	bt_put_unaligned(htobl(src), (uint32_t *) dst);
+}
+
+void att_data_list_free(struct att_data_list *list);
+
+const char *att_ecode2str(uint8_t status);
+uint16_t enc_read_by_grp_req(uint16_t start, uint16_t end, uuid_t *uuid,
+							uint8_t *pdu, int len);
+uint16_t dec_read_by_grp_req(const uint8_t *pdu, int len, uint16_t *start,
+						uint16_t *end, uuid_t *uuid);
+uint16_t enc_read_by_grp_resp(struct att_data_list *list, uint8_t *pdu, int len);
+uint16_t enc_find_by_type_req(uint16_t start, uint16_t end, uuid_t *uuid,
+							uint8_t *pdu, int len);
+struct att_data_list *dec_read_by_grp_resp(const uint8_t *pdu, int len);
+uint16_t enc_read_by_type_req(uint16_t start, uint16_t end, uuid_t *uuid,
+							uint8_t *pdu, int len);
+uint16_t dec_read_by_type_req(const uint8_t *pdu, int len, uint16_t *start,
+						uint16_t *end, uuid_t *uuid);
+uint16_t enc_read_by_type_resp(struct att_data_list *list, uint8_t *pdu,
+								int len);
+uint16_t enc_write_cmd(uint16_t handle, const uint8_t *value, int vlen,
+							uint8_t *pdu, int len);
+uint16_t dec_write_cmd(const uint8_t *pdu, int len, uint16_t *handle,
+						uint8_t *value, int *vlen);
+struct att_data_list *dec_read_by_type_resp(const uint8_t *pdu, int len);
+uint16_t enc_write_req(uint16_t handle, const uint8_t *value, int vlen,
+							uint8_t *pdu, int len);
+uint16_t dec_write_req(const uint8_t *pdu, int len, uint16_t *handle,
+						uint8_t *value, int *vlen);
+uint16_t enc_read_req(uint16_t handle, uint8_t *pdu, int len);
+uint16_t dec_read_req(const uint8_t *pdu, int len, uint16_t *handle);
+uint16_t enc_read_resp(uint8_t *value, int vlen, uint8_t *pdu, int len);
+uint16_t dec_read_resp(const uint8_t *pdu, int len, uint8_t *value, int *vlen);
+uint16_t enc_error_resp(uint8_t opcode, uint16_t handle, uint8_t status,
+							uint8_t *pdu, int len);
+uint16_t enc_find_info_req(uint16_t start, uint16_t end, uint8_t *pdu, int len);
+uint16_t dec_find_info_req(const uint8_t *pdu, int len, uint16_t *start,
+								uint16_t *end);
+uint16_t enc_find_info_resp(uint8_t format, struct att_data_list *list,
+							uint8_t *pdu, int len);
+struct att_data_list *dec_find_info_resp(const uint8_t *pdu, int len,
+							uint8_t *format);
+uint16_t enc_notification(struct attribute *a, uint8_t *pdu, int len);
+uint16_t enc_indication(struct attribute *a, uint8_t *pdu, int len);
+struct attribute *dec_indication(const uint8_t *pdu, int len);
+uint16_t enc_confirmation(uint8_t *pdu, int len);
+
+uint16_t enc_mtu_req(uint16_t mtu, uint8_t *pdu, int len);
+uint16_t dec_mtu_req(const uint8_t *pdu, int len, uint16_t *mtu);
+uint16_t enc_mtu_resp(uint16_t mtu, uint8_t *pdu, int len);
+uint16_t dec_mtu_resp(const uint8_t *pdu, int len, uint16_t *mtu);
diff --git a/src/gatt.c b/src/gatt.c
new file mode 100644
index 0000000..24ec990
--- /dev/null
+++ b/src/gatt.c
@@ -0,0 +1,113 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2010  Nokia Corporation
+ *  Copyright (C) 2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  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
+ *
+ */
+
+#include <stdint.h>
+#include <glib.h>
+#include <bluetooth/sdp.h>
+#include <bluetooth/sdp_lib.h>
+
+#include "att.h"
+#include "gattrib.h"
+#include "gatt.h"
+
+guint gatt_discover_primary(GAttrib *attrib, uint16_t start,
+		uint16_t end, GAttribResultFunc func, gpointer user_data)
+{
+	uint8_t pdu[ATT_DEFAULT_MTU];
+	uuid_t uuid;
+	guint16 plen;
+
+	sdp_uuid16_create(&uuid, GATT_PRIM_SVC_UUID);
+
+	plen = enc_read_by_grp_req(start, end, &uuid, pdu, sizeof(pdu));
+	if (plen == 0)
+		return 0;
+
+	return g_attrib_send(attrib, ATT_OP_READ_BY_GROUP_REQ,
+					pdu, plen, func, user_data, NULL);
+}
+
+guint gatt_discover_char(GAttrib *attrib, uint16_t start, uint16_t end,
+				GAttribResultFunc func, gpointer user_data)
+{
+	uint8_t pdu[ATT_DEFAULT_MTU];
+	uuid_t uuid;
+	guint16 plen;
+
+	sdp_uuid16_create(&uuid, GATT_CHARAC_UUID);
+
+	plen = enc_read_by_type_req(start, end, &uuid, pdu, sizeof(pdu));
+	if (plen == 0)
+		return 0;
+
+	return g_attrib_send(attrib, ATT_OP_READ_BY_TYPE_REQ,
+					pdu, plen, func, user_data, NULL);
+}
+
+guint gatt_read_char(GAttrib *attrib, uint16_t handle, GAttribResultFunc func,
+							gpointer user_data)
+{
+	uint8_t pdu[ATT_DEFAULT_MTU];
+	guint16 plen;
+
+	plen = enc_read_req(handle, pdu, sizeof(pdu));
+	return g_attrib_send(attrib, ATT_OP_READ_REQ, pdu, plen, func,
+							user_data, NULL);
+}
+
+guint gatt_write_char(GAttrib *attrib, uint16_t handle, uint8_t *value,
+			int vlen, GAttribResultFunc func, gpointer user_data)
+{
+	uint8_t pdu[ATT_DEFAULT_MTU];
+	guint16 plen;
+
+	plen = enc_write_req(handle, value, vlen, pdu, sizeof(pdu));
+	return g_attrib_send(attrib, ATT_OP_WRITE_REQ, pdu, plen, func,
+							user_data, NULL);
+}
+
+guint gatt_find_info(GAttrib *attrib, uint16_t start, uint16_t end,
+				GAttribResultFunc func, gpointer user_data)
+{
+	uint8_t pdu[ATT_DEFAULT_MTU];
+	guint16 plen;
+
+	plen = enc_find_info_req(start, end, pdu, sizeof(pdu));
+	if (plen == 0)
+		return 0;
+
+	return g_attrib_send(attrib, ATT_OP_FIND_INFO_REQ, pdu, plen, func,
+							user_data, NULL);
+}
+
+guint gatt_write_cmd(GAttrib *attrib, uint16_t handle, uint8_t *value, int vlen,
+				GDestroyNotify notify, gpointer user_data)
+{
+	uint8_t pdu[ATT_DEFAULT_MTU];
+	guint16 plen;
+
+	plen = enc_write_cmd(handle, value, vlen, pdu, sizeof(pdu));
+	return g_attrib_send(attrib, ATT_OP_WRITE_CMD, pdu, plen, NULL,
+							user_data, notify);
+}
diff --git a/src/gatt.h b/src/gatt.h
new file mode 100644
index 0000000..f1599c2
--- /dev/null
+++ b/src/gatt.h
@@ -0,0 +1,43 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2010  Nokia Corporation
+ *  Copyright (C) 2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  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
+ *
+ */
+
+#define GATT_CID 4
+
+guint gatt_discover_primary(GAttrib *attrib, uint16_t start,
+		uint16_t end, GAttribResultFunc func, gpointer user_data);
+
+guint gatt_discover_char(GAttrib *attrib, uint16_t start, uint16_t end,
+				GAttribResultFunc func, gpointer user_data);
+
+guint gatt_read_char(GAttrib *attrib, uint16_t handle, GAttribResultFunc func,
+							gpointer user_data);
+
+guint gatt_write_char(GAttrib *attrib, uint16_t handle, uint8_t *value,
+			int vlen, GAttribResultFunc func, gpointer user_data);
+
+guint gatt_find_info(GAttrib *attrib, uint16_t start, uint16_t end,
+				GAttribResultFunc func, gpointer user_data);
+
+guint gatt_write_cmd(GAttrib *attrib, uint16_t handle, uint8_t *value, int vlen,
+				GDestroyNotify notify, gpointer user_data);
diff --git a/src/gattrib.c b/src/gattrib.c
new file mode 100644
index 0000000..ed18168
--- /dev/null
+++ b/src/gattrib.c
@@ -0,0 +1,535 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2010  Nokia Corporation
+ *  Copyright (C) 2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  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
+ *
+ */
+
+#include <stdint.h>
+#include <string.h>
+#include <glib.h>
+
+#include <stdio.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/sdp.h>
+
+#include "att.h"
+#include "gattrib.h"
+
+struct _GAttrib {
+	GIOChannel *io;
+	gint refs;
+	gint mtu;
+	guint read_watch;
+	guint write_watch;
+	GQueue *queue;
+	GSList *events;
+	guint next_cmd_id;
+	guint next_evt_id;
+	GDestroyNotify destroy;
+	GAttribDisconnectFunc disconnect;
+	gpointer destroy_user_data;
+	gpointer disc_user_data;
+};
+
+struct command {
+	guint id;
+	guint8 opcode;
+	guint8 *pdu;
+	guint16 len;
+	guint8 expected;
+	gboolean sent;
+	GAttribResultFunc func;
+	gpointer user_data;
+	GDestroyNotify notify;
+};
+
+struct event {
+	guint id;
+	guint8 expected;
+	GAttribNotifyFunc func;
+	gpointer user_data;
+	GDestroyNotify notify;
+};
+
+static guint8 opcode2expected(guint8 opcode)
+{
+	switch (opcode) {
+	case ATT_OP_MTU_REQ:
+		return ATT_OP_MTU_RESP;
+
+	case ATT_OP_FIND_INFO_REQ:
+		return ATT_OP_FIND_INFO_RESP;
+
+	case ATT_OP_FIND_BY_TYPE_REQ:
+		return ATT_OP_FIND_BY_TYPE_RESP;
+
+	case ATT_OP_READ_BY_TYPE_REQ:
+		return ATT_OP_READ_BY_TYPE_RESP;
+
+	case ATT_OP_READ_REQ:
+		return ATT_OP_READ_RESP;
+
+	case ATT_OP_READ_BLOB_REQ:
+		return ATT_OP_READ_BLOB_RESP;
+
+	case ATT_OP_READ_MULTI_REQ:
+		return ATT_OP_READ_MULTI_RESP;
+
+	case ATT_OP_READ_BY_GROUP_REQ:
+		return ATT_OP_READ_BY_GROUP_RESP;
+
+	case ATT_OP_WRITE_REQ:
+		return ATT_OP_WRITE_RESP;
+
+	case ATT_OP_PREP_WRITE_REQ:
+		return ATT_OP_PREP_WRITE_RESP;
+
+	case ATT_OP_EXEC_WRITE_REQ:
+		return ATT_OP_EXEC_WRITE_RESP;
+
+	case ATT_OP_HANDLE_IND:
+		return ATT_OP_HANDLE_CNF;
+	}
+
+	return 0;
+}
+
+static gboolean is_response(guint8 opcode)
+{
+	switch (opcode) {
+	case ATT_OP_ERROR:
+	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:
+		return TRUE;
+	}
+
+	return FALSE;
+}
+
+GAttrib *g_attrib_ref(GAttrib *attrib)
+{
+	if (!attrib)
+		return NULL;
+
+	g_atomic_int_inc(&attrib->refs);
+
+	return attrib;
+}
+
+static void command_destroy(struct command *cmd)
+{
+	if (cmd->notify)
+		cmd->notify(cmd->user_data);
+
+	g_free(cmd->pdu);
+	g_free(cmd);
+}
+
+static void event_destroy(struct event *evt)
+{
+	if (evt->notify)
+		evt->notify(evt->user_data);
+
+	g_free(evt);
+}
+
+void g_attrib_unref(GAttrib *attrib)
+{
+	GSList *l;
+	struct command *c;
+
+	if (!attrib)
+		return;
+
+	if (g_atomic_int_dec_and_test(&attrib->refs) == FALSE)
+		return;
+
+	while ((c = g_queue_pop_head(attrib->queue)))
+		command_destroy(c);
+
+	attrib->queue = NULL;
+
+	for (l = attrib->events; l; l = l->next)
+		event_destroy(l->data);
+
+	g_slist_free(attrib->events);
+	attrib->events = NULL;
+
+	if (attrib->write_watch > 0)
+		g_source_remove(attrib->write_watch);
+
+	if (attrib->read_watch > 0) {
+		g_source_remove(attrib->read_watch);
+		g_io_channel_unref(attrib->io);
+	}
+
+
+	if (attrib->destroy)
+		attrib->destroy(attrib->destroy_user_data);
+
+	g_free(attrib);
+}
+
+gboolean g_attrib_set_disconnect_function(GAttrib *attrib,
+		GAttribDisconnectFunc disconnect, gpointer user_data)
+{
+	if (attrib == NULL)
+		return FALSE;
+
+	attrib->disconnect = disconnect;
+	attrib->disc_user_data = user_data;
+
+	return TRUE;
+}
+
+gboolean g_attrib_set_destroy_function(GAttrib *attrib,
+		GDestroyNotify destroy, gpointer user_data)
+{
+	if (attrib == NULL)
+		return FALSE;
+
+	attrib->destroy = destroy;
+	attrib->destroy_user_data = user_data;
+
+	return TRUE;
+}
+
+static gboolean can_write_data(GIOChannel *io, GIOCondition cond,
+								gpointer data)
+{
+	struct _GAttrib *attrib = data;
+	struct command *cmd;
+	GError *gerr = NULL;
+	gsize len;
+	GIOStatus iostat;
+
+	if (cond & (G_IO_HUP | G_IO_ERR | G_IO_NVAL)) {
+		if (attrib->disconnect)
+			attrib->disconnect(attrib->disc_user_data);
+
+		return FALSE;
+	}
+
+	cmd = g_queue_peek_head(attrib->queue);
+	if (cmd == NULL)
+		return FALSE;
+
+	iostat = g_io_channel_write_chars(io, (gchar *) cmd->pdu, cmd->len,
+								&len, &gerr);
+	if (iostat != G_IO_STATUS_NORMAL)
+		return FALSE;
+
+	g_io_channel_flush(io, NULL);
+
+	if (cmd->expected == 0) {
+		g_queue_pop_head(attrib->queue);
+		command_destroy(cmd);
+
+		return TRUE;
+	}
+
+	cmd->sent = TRUE;
+
+	return FALSE;
+}
+
+static void destroy_sender(gpointer data)
+{
+	struct _GAttrib *attrib = data;
+
+	attrib->write_watch = 0;
+}
+
+static void wake_up_sender(struct _GAttrib *attrib)
+{
+	if (attrib->write_watch == 0)
+		attrib->write_watch = g_io_add_watch_full(attrib->io,
+			G_PRIORITY_DEFAULT, G_IO_OUT, can_write_data,
+			attrib, destroy_sender);
+}
+
+static gboolean received_data(GIOChannel *io, GIOCondition cond, gpointer data)
+{
+	struct _GAttrib *attrib = data;
+	struct command *cmd = NULL;
+	GSList *l;
+	uint8_t buf[512], status;
+	gsize len;
+	GIOStatus iostat;
+
+	if (cond & (G_IO_HUP | G_IO_ERR | G_IO_NVAL)) {
+		attrib->read_watch = 0;
+		if (attrib->disconnect)
+			attrib->disconnect(attrib->disc_user_data);
+		return FALSE;
+	}
+
+	memset(buf, 0, sizeof(buf));
+
+	iostat = g_io_channel_read_chars(io, (gchar *) buf, sizeof(buf),
+								&len, NULL);
+	if (iostat != G_IO_STATUS_NORMAL) {
+		status = ATT_ECODE_IO;
+		goto done;
+	}
+
+	for (l = attrib->events; l; l = l->next) {
+		struct event *evt = l->data;
+
+		if (evt->expected == buf[0] ||
+					evt->expected == GATTRIB_ALL_EVENTS)
+			evt->func(buf, len, evt->user_data);
+	}
+
+	if (is_response(buf[0]) == FALSE)
+		return TRUE;
+
+	cmd = g_queue_pop_head(attrib->queue);
+	if (cmd == NULL) {
+		/* Keep the watch if we have events to report */
+		return attrib->events != NULL;
+	}
+
+	if (buf[0] == ATT_OP_ERROR) {
+		status = buf[4];
+		goto done;
+	}
+
+	if (cmd->expected != buf[0]) {
+		status = ATT_ECODE_IO;
+		goto done;
+	}
+
+	status = 0;
+
+done:
+	if (attrib->queue && g_queue_is_empty(attrib->queue) == FALSE)
+		wake_up_sender(attrib);
+
+	if (cmd) {
+		if (cmd->func)
+			cmd->func(status, buf, len, cmd->user_data);
+
+		command_destroy(cmd);
+	}
+
+	return TRUE;
+}
+
+GAttrib *g_attrib_new(GIOChannel *io)
+{
+	struct _GAttrib *attrib;
+
+	g_io_channel_set_encoding(io, NULL, NULL);
+
+	attrib = g_try_new0(struct _GAttrib, 1);
+	if (attrib == NULL)
+		return NULL;
+
+	attrib->io = g_io_channel_ref(io);
+	attrib->mtu = 512;
+	attrib->queue = g_queue_new();
+
+	attrib->read_watch = g_io_add_watch(attrib->io,
+			G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+			received_data, attrib);
+
+	return g_attrib_ref(attrib);
+}
+
+guint g_attrib_send(GAttrib *attrib, guint8 opcode, const guint8 *pdu,
+				guint16 len, GAttribResultFunc func,
+				gpointer user_data, GDestroyNotify notify)
+{
+	struct command *c;
+
+	c = g_try_new0(struct command, 1);
+	if (c == NULL)
+		return 0;
+
+	c->opcode = opcode;
+	c->expected = opcode2expected(opcode);
+	c->pdu = g_malloc(len);
+	memcpy(c->pdu, pdu, len);
+	c->len = len;
+	c->func = func;
+	c->user_data = user_data;
+	c->notify = notify;
+	c->id = ++attrib->next_cmd_id;
+
+	g_queue_push_tail(attrib->queue, c);
+
+	if (g_queue_get_length(attrib->queue) == 1)
+		wake_up_sender(attrib);
+
+	return c->id;
+}
+
+static gint command_cmp_by_id(gconstpointer a, gconstpointer b)
+{
+	const struct command *cmd = a;
+	guint id = GPOINTER_TO_UINT(b);
+
+	return cmd->id - id;
+}
+
+gboolean g_attrib_cancel(GAttrib *attrib, guint id)
+{
+	GList *l;
+	struct command *cmd;
+
+	if (attrib == NULL || attrib->queue == NULL)
+		return FALSE;
+
+	l = g_queue_find_custom(attrib->queue, GUINT_TO_POINTER(id),
+							command_cmp_by_id);
+	if (l == NULL)
+		return FALSE;
+
+	cmd = l->data;
+
+	if (cmd == g_queue_peek_head(attrib->queue) && cmd->sent)
+		cmd->func = NULL;
+	else {
+		g_queue_remove(attrib->queue, cmd);
+		command_destroy(cmd);
+	}
+
+	return TRUE;
+}
+
+gboolean g_attrib_cancel_all(GAttrib *attrib)
+{
+	struct command *c, *head = NULL;
+	gboolean first = TRUE;
+
+	if (attrib == NULL || attrib->queue == NULL)
+		return FALSE;
+
+	while ((c = g_queue_pop_head(attrib->queue))) {
+		if (first && c->sent) {
+			/* If the command was sent ignore its callback ... */
+			c->func = NULL;
+			head = c;
+			continue;
+		}
+
+		first = FALSE;
+		command_destroy(c);
+	}
+
+	if (head) {
+		/* ... and put it back in the queue */
+		g_queue_push_head(attrib->queue, head);
+	}
+
+	return TRUE;
+}
+
+gboolean g_attrib_set_debug(GAttrib *attrib,
+		GAttribDebugFunc func, gpointer user_data)
+{
+	return TRUE;
+}
+
+guint g_attrib_register(GAttrib *attrib, guint8 opcode,
+				GAttribNotifyFunc func, gpointer user_data,
+				GDestroyNotify notify)
+{
+	struct event *event;
+
+	event = g_try_new0(struct event, 1);
+	if (event == NULL)
+		return 0;
+
+	event->expected = opcode;
+	event->func = func;
+	event->user_data = user_data;
+	event->notify = notify;
+	event->id = ++attrib->next_evt_id;
+
+	attrib->events = g_slist_append(attrib->events, event);
+
+	return event->id;
+}
+
+static gint event_cmp_by_id(gconstpointer a, gconstpointer b)
+{
+	const struct event *evt = a;
+	guint id = GPOINTER_TO_UINT(b);
+
+	return evt->id - id;
+}
+
+gboolean g_attrib_unregister(GAttrib *attrib, guint id)
+{
+	struct event *evt;
+	GSList *l;
+
+	l = g_slist_find_custom(attrib->events, GUINT_TO_POINTER(id),
+							event_cmp_by_id);
+	if (l == NULL)
+		return FALSE;
+
+	evt = l->data;
+
+	attrib->events = g_slist_remove(attrib->events, evt);
+
+	if (evt->notify)
+		evt->notify(evt->user_data);
+
+	g_free(evt);
+
+	return TRUE;
+}
+
+gboolean g_attrib_unregister_all(GAttrib *attrib)
+{
+	GSList *l;
+
+	if (attrib->events == NULL)
+		return FALSE;
+
+	for (l = attrib->events; l; l = l->next) {
+		struct event *evt = l->data;
+
+		if (evt->notify)
+			evt->notify(evt->user_data);
+
+		g_free(evt);
+	}
+
+	g_slist_free(attrib->events);
+	attrib->events = NULL;
+
+	return TRUE;
+}
diff --git a/src/gattrib.h b/src/gattrib.h
new file mode 100644
index 0000000..4306ca4
--- /dev/null
+++ b/src/gattrib.h
@@ -0,0 +1,72 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2010  Nokia Corporation
+ *  Copyright (C) 2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  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
+ *
+ */
+#ifndef __GATTRIB_H
+#define __GATTRIB_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define GATTRIB_ALL_EVENTS 0xFF
+
+struct _GAttrib;
+typedef struct _GAttrib GAttrib;
+
+typedef void (*GAttribResultFunc) (guint8 status, const guint8 *pdu,
+					guint16 len, gpointer user_data);
+typedef void (*GAttribDisconnectFunc)(gpointer user_data);
+typedef void (*GAttribDebugFunc)(const char *str, gpointer user_data);
+typedef void (*GAttribNotifyFunc)(const guint8 *pdu, guint16 len,
+							gpointer user_data);
+
+GAttrib *g_attrib_new(GIOChannel *io);
+GAttrib *g_attrib_ref(GAttrib *attrib);
+void g_attrib_unref(GAttrib *attrib);
+
+gboolean g_attrib_set_disconnect_function(GAttrib *attrib,
+		GAttribDisconnectFunc disconnect, gpointer user_data);
+
+gboolean g_attrib_set_destroy_function(GAttrib *attrib,
+		GDestroyNotify destroy, gpointer user_data);
+
+guint g_attrib_send(GAttrib *attrib, guint8 opcode, const guint8 *pdu,
+				guint16 len, GAttribResultFunc func,
+				gpointer user_data, GDestroyNotify notify);
+gboolean g_attrib_cancel(GAttrib *attrib, guint id);
+gboolean g_attrib_cancel_all(GAttrib *attrib);
+
+gboolean g_attrib_set_debug(GAttrib *attrib,
+		GAttribDebugFunc func, gpointer user_data);
+
+guint g_attrib_register(GAttrib *attrib, guint8 opcode,
+		GAttribNotifyFunc func, gpointer user_data,
+					GDestroyNotify notify);
+
+gboolean g_attrib_unregister(GAttrib *attrib, guint id);
+gboolean g_attrib_unregister_all(GAttrib *attrib);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
-- 
1.7.3.2


^ permalink raw reply related

* [PATCH] Fix invalid reference to GATT service structure
From: Claudio Takahasi @ 2010-11-04 19:43 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Claudio Takahasi
In-Reply-To: <1288899810-18722-1-git-send-email-claudio.takahasi@openbossa.org>

---
 attrib/client.c |    9 ++++-----
 1 files changed, 4 insertions(+), 5 deletions(-)

diff --git a/attrib/client.c b/attrib/client.c
index bcc903b..1f2c217 100644
--- a/attrib/client.c
+++ b/attrib/client.c
@@ -1342,13 +1342,9 @@ int attrib_client_register(struct btd_device *device, int psm)
 	bacpy(&gatt->dba, &dba);
 	gatt->psm = psm;
 
-	gatt_services = g_slist_append(gatt_services, gatt);
-
-	/* FIXME: we should also listen for incoming connections */
-
 	if (load_primary_services(gatt)) {
 		DBG("Primary services loaded");
-		return 0;
+		goto done;
 	}
 
 	if (psm < 0) {
@@ -1385,6 +1381,9 @@ int attrib_client_register(struct btd_device *device, int psm)
 	g_attrib_set_disconnect_function(gatt->attrib, attrib_disconnect,
 									gatt);
 
+done:
+	gatt_services = g_slist_append(gatt_services, gatt);
+
 	return 0;
 }
 
-- 
1.7.3.2


^ permalink raw reply related

* [PATCH] Enable GATT over LE link on the attribute client
From: Claudio Takahasi @ 2010-11-04 19:43 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Claudio Takahasi
In-Reply-To: <1288899810-18722-1-git-send-email-claudio.takahasi@openbossa.org>

---
 attrib/client.c   |   22 ++++++++++++----------
 attrib/gatt.h     |    2 ++
 attrib/gatttool.c |    1 -
 3 files changed, 14 insertions(+), 11 deletions(-)

diff --git a/attrib/client.c b/attrib/client.c
index cd720e6..bcc903b 100644
--- a/attrib/client.c
+++ b/attrib/client.c
@@ -1352,23 +1352,25 @@ int attrib_client_register(struct btd_device *device, int psm)
 	}
 
 	if (psm < 0) {
-		/*
-		 * FIXME: when PSM is not given means that L2CAP fixed
-		 * channel shall be used. For this case, ATT CID(0x0004).
-		 */
-
-		DBG("GATT over LE");
-
-		return 0;
-	}
+		io = bt_io_connect(BT_IO_L2CAP, connect_cb, gatt, NULL, &gerr,
+					BT_IO_OPT_SOURCE_BDADDR, &sba,
+					BT_IO_OPT_DEST_BDADDR, &dba,
+					BT_IO_OPT_CID, GATT_CID,
+					BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
+					BT_IO_OPT_INVALID);
 
-	io = bt_io_connect(BT_IO_L2CAP, connect_cb, gatt, NULL, &gerr,
+			DBG("GATT over Low Energy");
+	} else {
+		io = bt_io_connect(BT_IO_L2CAP, connect_cb, gatt, NULL, &gerr,
 					BT_IO_OPT_SOURCE_BDADDR, &sba,
 					BT_IO_OPT_DEST_BDADDR, &dba,
 					BT_IO_OPT_PSM, psm,
 					BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
 					BT_IO_OPT_INVALID);
 
+		DBG("GATT over Basic Rate");
+	}
+
 	if (!io) {
 		error("%s", gerr->message);
 		g_error_free(gerr);
diff --git a/attrib/gatt.h b/attrib/gatt.h
index a357f58..f1599c2 100644
--- a/attrib/gatt.h
+++ b/attrib/gatt.h
@@ -22,6 +22,8 @@
  *
  */
 
+#define GATT_CID 4
+
 guint gatt_discover_primary(GAttrib *attrib, uint16_t start,
 		uint16_t end, GAttribResultFunc func, gpointer user_data);
 
diff --git a/attrib/gatttool.c b/attrib/gatttool.c
index 2de3f8b..b9f5138 100644
--- a/attrib/gatttool.c
+++ b/attrib/gatttool.c
@@ -45,7 +45,6 @@
 
 /* Minimum MTU for L2CAP connections over BR/EDR */
 #define ATT_MIN_MTU_L2CAP 48
-#define GATT_CID 4
 
 static gchar *opt_src = NULL;
 static gchar *opt_dst = NULL;
-- 
1.7.3.2


^ permalink raw reply related

* [PATCH] Move set_nonblocking function to audio/unix.c
From: Claudio Takahasi @ 2010-11-04 19:43 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Claudio Takahasi

---
 audio/unix.c      |   20 ++++++++++++++++++++
 src/glib-helper.c |   20 --------------------
 src/glib-helper.h |    2 --
 3 files changed, 20 insertions(+), 22 deletions(-)

diff --git a/audio/unix.c b/audio/unix.c
index ad822bd..62eee31 100644
--- a/audio/unix.c
+++ b/audio/unix.c
@@ -27,6 +27,7 @@
 #endif
 
 #include <stdio.h>
+#include <fcntl.h>
 #include <sys/socket.h>
 #include <sys/un.h>
 #include <stdlib.h>
@@ -115,6 +116,25 @@ static void client_free(struct unix_client *client)
 	g_free(client);
 }
 
+static int set_nonblocking(int fd)
+{
+	long arg;
+
+	arg = fcntl(fd, F_GETFL);
+	if (arg < 0)
+		return -errno;
+
+	/* Return if already nonblocking */
+	if (arg & O_NONBLOCK)
+		return 0;
+
+	arg |= O_NONBLOCK;
+	if (fcntl(fd, F_SETFL, arg) < 0)
+		return -errno;
+
+	return 0;
+}
+
 /* Pass file descriptor through local domain sockets (AF_LOCAL, formerly
  * AF_UNIX) and the sendmsg() system call with the cmsg_type field of a "struct
  * cmsghdr" set to SCM_RIGHTS and the data being an integer value equal to the
diff --git a/src/glib-helper.c b/src/glib-helper.c
index b3c5003..9d76626 100644
--- a/src/glib-helper.c
+++ b/src/glib-helper.c
@@ -27,7 +27,6 @@
 
 #include <stdlib.h>
 #include <errno.h>
-#include <fcntl.h>
 #include <unistd.h>
 #include <sys/ioctl.h>
 #include <sys/socket.h>
@@ -113,25 +112,6 @@ static void cache_sdp_session(bdaddr_t *src, bdaddr_t *dst,
 						cached);
 }
 
-int set_nonblocking(int fd)
-{
-	long arg;
-
-	arg = fcntl(fd, F_GETFL);
-	if (arg < 0)
-		return -errno;
-
-	/* Return if already nonblocking */
-	if (arg & O_NONBLOCK)
-		return 0;
-
-	arg |= O_NONBLOCK;
-	if (fcntl(fd, F_SETFL, arg) < 0)
-		return -errno;
-
-	return 0;
-}
-
 struct search_context {
 	bdaddr_t		src;
 	bdaddr_t		dst;
diff --git a/src/glib-helper.h b/src/glib-helper.h
index 8a334e9..e89c2c6 100644
--- a/src/glib-helper.h
+++ b/src/glib-helper.h
@@ -21,8 +21,6 @@
  *
  */
 
-int set_nonblocking(int fd);
-
 typedef void (*bt_callback_t) (sdp_list_t *recs, int err, gpointer user_data);
 typedef void (*bt_destroy_t) (gpointer user_data);
 
-- 
1.7.3.2


^ permalink raw reply related

* Re: [PATCH] Fix handling call waiting indicators in telephony
From: Johan Hedberg @ 2010-11-04 18:18 UTC (permalink / raw)
  To: Lukasz Pawlik; +Cc: linux-bluetooth
In-Reply-To: <1288882837-9163-1-git-send-email-lucas.pawlik@gmail.com>

Hi Lukasz,

On Thu, Nov 04, 2010, Lukasz Pawlik wrote:
> Previously +CIEV: "callsetup" was sent before +CCWA: (call waiting)
> notification. According to the HFP specification AG reports new
> call waiting by sending +CCWA before +CIEV indicator. Some HF did
> not handle properly ending active call after rejecting 2nd incoming call
> if "callsetup" indicator was sent before call waiting.
> ---
>  audio/telephony-maemo6.c |    6 +++---
>  1 files changed, 3 insertions(+), 3 deletions(-)

Pushed upstream. Thanks.

Johan

^ permalink raw reply

* Re: [PATCH] Fix not ignoring case of uuid given to RegisterEndpoint
From: Johan Hedberg @ 2010-11-04 18:17 UTC (permalink / raw)
  To: Luiz Augusto von Dentz; +Cc: linux-bluetooth
In-Reply-To: <1288880990-2125-1-git-send-email-luiz.dentz@gmail.com>

Hi Luiz,

On Thu, Nov 04, 2010, Luiz Augusto von Dentz wrote:
> From: Luiz Augusto von Dentz <luiz.dentz-von@nokia.com>
> 
> ---
>  audio/media.c     |    6 +++---
>  audio/transport.c |    8 ++++----
>  2 files changed, 7 insertions(+), 7 deletions(-)

Pushed upstream. Thanks.

Johan

^ permalink raw reply

* Re: [PATCH] Fix add disconnect watch in connecting state
From: Johan Hedberg @ 2010-11-04 18:16 UTC (permalink / raw)
  To: Daniel Örstadius; +Cc: linux-bluetooth
In-Reply-To: <AANLkTikyPtikmH=ep2va2iLke9NoteTr5wpThfR6v=vf@mail.gmail.com>

Hi Daniel,

On Thu, Nov 04, 2010, Daniel Örstadius wrote:
> If disconnect_cb is added only in the connected state, the callback
> will not be triggered if Device.Disconnected is called during a
> connection setup and the RFCOMM channel of HFP will not be cleanly
> disconnected.
> ---
>  audio/device.c |    2 +-
>  1 files changed, 1 insertions(+), 1 deletions(-)
> 
> diff --git a/audio/device.c b/audio/device.c
> index 9554c7b..2e75538 100644
> --- a/audio/device.c
> +++ b/audio/device.c
> @@ -231,7 +231,7 @@ static void device_set_state(struct audio_device *dev, audio_state_t new_state)
>  							priv->dc_id);
>  			priv->dc_id = 0;
>  		}
> -	} else if (new_state == AUDIO_STATE_CONNECTED)
> +	} else
>  		priv->dc_id = device_add_disconnect_watch(dev->btd_dev,
>  						disconnect_cb, dev, NULL);
>  

This doesn't seem quite right to me. Aren't you now adding a disconnect
callback twice: once for CONNECTING and a second time for CONNECTED? It
seems like you should only add it when new_state == CONNECTING, right?

Johan

^ permalink raw reply

* Re: [PATCH] Fix status problem after pulling empty call history
From: Johan Hedberg @ 2010-11-04 18:11 UTC (permalink / raw)
  To: Rafal Michalski; +Cc: linux-bluetooth
In-Reply-To: <1288871880-5857-1-git-send-email-michalski.raf@gmail.com>

Hi Rafal,

On Thu, Nov 04, 2010, Rafal Michalski wrote:
> Problem with "OK" status after pulling phonebook for empty call history
> (cch) is fixed by this patch. Previously "OK" status was received even
> for empty (as it normally does for non-empty) call history and now
> "Not Found" status is received in case when there is no call event.
> ---
>  plugins/pbap.c |    2 +-
>  1 files changed, 1 insertions(+), 1 deletions(-)

Pushed upstream. Thanks.

Johan

^ permalink raw reply

* [PATCH] Fix handling call waiting indicators in telephony
From: Lukasz Pawlik @ 2010-11-04 15:00 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Lukasz Pawlik

Previously +CIEV: "callsetup" was sent before +CCWA: (call waiting)
notification. According to the HFP specification AG reports new
call waiting by sending +CCWA before +CIEV indicator. Some HF did
not handle properly ending active call after rejecting 2nd incoming call
if "callsetup" indicator was sent before call waiting.
---
 audio/telephony-maemo6.c |    6 +++---
 1 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/audio/telephony-maemo6.c b/audio/telephony-maemo6.c
index 33fd13f..72c8e36 100644
--- a/audio/telephony-maemo6.c
+++ b/audio/telephony-maemo6.c
@@ -914,9 +914,6 @@ static void handle_incoming_call(DBusMessage *msg)
 	g_free(call->number);
 	call->number = g_strdup(number);
 
-	telephony_update_indicator(maemo_indicators, "callsetup",
-					EV_CALLSETUP_INCOMING);
-
 	if (find_call_with_status(CSD_CALL_STATUS_ACTIVE) ||
 			find_call_with_status(CSD_CALL_STATUS_HOLD))
 		telephony_call_waiting_ind(call->number,
@@ -924,6 +921,9 @@ static void handle_incoming_call(DBusMessage *msg)
 	else
 		telephony_incoming_call_ind(call->number,
 						number_type(call->number));
+
+	telephony_update_indicator(maemo_indicators, "callsetup",
+					EV_CALLSETUP_INCOMING);
 }
 
 static void handle_outgoing_call(DBusMessage *msg)
-- 
1.7.0.4


^ permalink raw reply related

* Re: [PATCH] Fix Maemo6 MCE: set state variable directly
From: Johan Hedberg @ 2010-11-04 14:41 UTC (permalink / raw)
  To: Daniel Örstadius; +Cc: linux-bluetooth
In-Reply-To: <AANLkTimpjr1Kc23zn=7uf0WNV5784ccPq8hWtBYrNADh@mail.gmail.com>

On Wed, Oct 20, 2010, Daniel Örstadius wrote:
> From: Daniel Orstadius <daniel.orstadius@nokia.com>
> Date: Wed, 20 Oct 2010 17:13:17 +0300
> Subject: [PATCH] Fix Maemo6 MCE: set state variable directly
> 
> If the state variable is not updated until mce_signal_callback and
> SetProperty(Powered) is called two times quickly, then the second
> call will not generate a request to change the radio state of the
> MCE if its corresponding call to adapter_powered occurs before the
> first triggering of mce_signal_callback.
> 
> With this patch two calls to the MCE are executed, although there
> might still be an unnecessary power cycle in that
> mce_signal_callback is also triggered twice.
> ---
>  plugins/maemo6.c |    4 +++-
>  1 files changed, 3 insertions(+), 1 deletions(-)

This patch has been pushed upstream after an offline discussion which
concluded that it should be safe to ignore the method reply from MCE in
this case.

Johan

^ permalink raw reply

* [PATCH] Fix not ignoring case of uuid given to RegisterEndpoint
From: Luiz Augusto von Dentz @ 2010-11-04 14:29 UTC (permalink / raw)
  To: linux-bluetooth

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

---
 audio/media.c     |    6 +++---
 audio/transport.c |    8 ++++----
 2 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/audio/media.c b/audio/media.c
index 661f81a..b6c90f9 100644
--- a/audio/media.c
+++ b/audio/media.c
@@ -190,19 +190,19 @@ static struct media_endpoint *media_endpoint_create(struct media_adapter *adapte
 	endpoint->size = size;
 	endpoint->adapter = adapter;
 
-	if (g_strcmp0(uuid, A2DP_SOURCE_UUID) == 0) {
+	if (strcasecmp(uuid, A2DP_SOURCE_UUID) == 0) {
 		endpoint->sep = a2dp_add_sep(&adapter->src,
 					AVDTP_SEP_TYPE_SOURCE, codec,
 					delay_reporting, endpoint);
 		if (endpoint->sep == NULL)
 			goto failed;
-	} else if (g_strcmp0(uuid, A2DP_SINK_UUID) == 0) {
+	} else if (strcasecmp(uuid, A2DP_SINK_UUID) == 0) {
 		endpoint->sep = a2dp_add_sep(&adapter->src,
 						AVDTP_SEP_TYPE_SINK, codec,
 						delay_reporting, endpoint);
 		if (endpoint->sep == NULL)
 			goto failed;
-	} else if (g_strcmp0(uuid, HFP_AG_UUID) == 0 ||
+	} else if (strcasecmp(uuid, HFP_AG_UUID) == 0 ||
 					g_strcmp0(uuid, HSP_AG_UUID) == 0)
 		endpoint->hs_watch = headset_add_state_cb(headset_state_changed,
 								endpoint);
diff --git a/audio/transport.c b/audio/transport.c
index 6d78b73..eda46e1 100644
--- a/audio/transport.c
+++ b/audio/transport.c
@@ -711,15 +711,15 @@ struct media_transport *media_transport_create(DBusConnection *conn,
 	transport->fd = -1;
 
 	uuid = media_endpoint_get_uuid(endpoint);
-	if (g_strcmp0(uuid, A2DP_SOURCE_UUID) == 0 ||
-			g_strcmp0(uuid, A2DP_SINK_UUID) == 0) {
+	if (strcasecmp(uuid, A2DP_SOURCE_UUID) == 0 ||
+			strcasecmp(uuid, A2DP_SINK_UUID) == 0) {
 		transport->resume = resume_a2dp;
 		transport->suspend = suspend_a2dp;
 		transport->cancel = cancel_a2dp;
 		transport->get_properties = get_properties_a2dp;
 		transport->set_property = set_property_a2dp;
-	} else if (g_strcmp0(uuid, HFP_AG_UUID) == 0 ||
-			g_strcmp0(uuid, HSP_AG_UUID) == 0) {
+	} else if (strcasecmp(uuid, HFP_AG_UUID) == 0 ||
+			strcasecmp(uuid, HSP_AG_UUID) == 0) {
 		transport->resume = resume_headset;
 		transport->suspend = suspend_headset;
 		transport->cancel = cancel_headset;
-- 
1.7.1


^ permalink raw reply related

* [PATCH v3] Add support for sending large PBAP response in many parts
From: Radoslaw Jablonski @ 2010-11-04 14:18 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Radoslaw Jablonski

Added file buffer to cache pull results - temporary file will be deleted
when response is sent. Also added partial_resp variable to pbap_session
for holding information if more data will be available from source later.
It was needed to know when sent -EAGAIN to obex, if currently is no data
available in the buffer.
---
 plugins/pbap.c |   89 +++++++++++++++++++++++++++++++++++++++++++++++++------
 1 files changed, 79 insertions(+), 10 deletions(-)

diff --git a/plugins/pbap.c b/plugins/pbap.c
index 3ea7d6b..6742ea7 100644
--- a/plugins/pbap.c
+++ b/plugins/pbap.c
@@ -116,6 +116,8 @@
   </attribute>								\
 </record>"
 
+#define PBAP_BUF_TEMPLATE "pbap_pullXXXXXX"
+
 struct aparam_header {
 	uint8_t tag;
 	uint8_t len;
@@ -143,6 +145,10 @@ struct pbap_session {
 	uint32_t find_handle;
 	GString *buffer;
 	struct cache cache;
+	gboolean partial_resp;
+	int fbuf_w;
+	int fbuf_r;
+	char *buf_path;
 };
 
 static const uint8_t PBAP_TARGET[TARGET_SIZE] = {
@@ -256,11 +262,27 @@ static void query_result(const char *buffer, size_t bufsize, int vcards,
 		return;
 	}
 
-	if (!pbap->buffer)
-		pbap->buffer = g_string_new_len(buffer, bufsize);
-	else
-		pbap->buffer = g_string_append_len(pbap->buffer, buffer,
-								bufsize);
+	if (pbap->fbuf_w < 0) {
+		/* Creating file buffer for results*/
+		pbap->buf_path = g_build_filename(g_get_tmp_dir(),
+						PBAP_BUF_TEMPLATE, NULL);
+		pbap->fbuf_w = g_mkstemp(pbap->buf_path);
+
+		if (pbap->fbuf_w < 0)
+			return -EPERM;
+	}
+
+	write(pbap->fbuf_w, buffer, bufsize);
+
+	/* If partial_resp will be set to TRUE, then we won't end transmission
+	 * after sending one part of results to the client via obex*/
+	pbap->partial_resp = missed ? TRUE : FALSE;
+
+	/* If no more data in future, we close file buffer right now*/
+	if (!pbap->partial_resp) {
+		close(pbap->fbuf_w);
+		pbap->fbuf_w = -1;
+	}
 
 	obex_object_set_io_flags(pbap, G_IO_IN, 0);
 }
@@ -549,6 +571,8 @@ static void *pbap_connect(struct obex_session *os, int *err)
 	pbap = g_new0(struct pbap_session, 1);
 	pbap->folder = g_strdup("/");
 	pbap->find_handle = PHONEBOOK_INVALID_HANDLE;
+	pbap->fbuf_r = -1;
+	pbap->fbuf_w = -1;
 
 	if (err)
 		*err = 0;
@@ -829,6 +853,27 @@ fail:
 	return NULL;
 }
 
+static ssize_t pbap_read_fbuf(struct pbap_session *pbap, void *buf,
+								size_t count)
+{
+	ssize_t len;
+
+	if (pbap->fbuf_r < 0) {
+		pbap->fbuf_r = open(pbap->buf_path, 0);
+
+		if(pbap->fbuf_r < 0)
+			return -EPERM;
+	}
+
+	len = read(pbap->fbuf_r, buf, count);
+
+	if (len == 0 && pbap->partial_resp)
+		/* More data available later */
+		return -EAGAIN;
+	else
+		return len;
+}
+
 static ssize_t vobject_pull_read(void *object, void *buf, size_t count,
 								uint8_t *hi)
 {
@@ -837,17 +882,23 @@ static ssize_t vobject_pull_read(void *object, void *buf, size_t count,
 	DBG("buffer %p maxlistcount %d", pbap->buffer,
 						pbap->params->maxlistcount);
 
-	if (!pbap->buffer)
+	if (!pbap->buf_path && !pbap->buffer)
+		/* No response available now (no memory/file buffer exist)*/
 		return -EAGAIN;
 
-	/* PhoneBookSize */
-	if (pbap->params->maxlistcount == 0)
+	/* Result from pb size query is very short (only number) so it makes no
+	 * sense to create file buffer for it - using memory buff */
+	if (pbap->params->maxlistcount == 0) {
+		/* PhoneBookSize */
 		*hi = OBEX_HDR_APPARAM;
-	else
+
+		return string_read(pbap->buffer, buf, count);
+	} else {
 		/* Stream data */
 		*hi = OBEX_HDR_BODY;
 
-	return string_read(pbap->buffer, buf, count);
+		return pbap_read_fbuf(pbap, buf, count);
+	}
 }
 
 static ssize_t vobject_list_read(void *object, void *buf, size_t count,
@@ -893,6 +944,24 @@ static int vobject_close(void *object)
 		pbap->buffer = NULL;
 	}
 
+	if (pbap->fbuf_r >= 0) {
+		close(pbap->fbuf_r);
+		pbap->fbuf_r = -1;
+	}
+
+	if (pbap->fbuf_w >= 0) {
+		close(pbap->fbuf_w);
+		pbap->fbuf_w = -1;
+	}
+
+	if (pbap->buf_path) {
+		/* remove file buffer for pull queries */
+		unlink(pbap->buf_path);
+
+		g_free(pbap->buf_path);
+		pbap->buf_path = NULL;
+	}
+
 	return 0;
 }
 
-- 
1.7.0.4


^ 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