Linux bluetooth development
 help / color / mirror / Atom feed
* [PATCH 4/4] Add simple-oobprovider for testing.
From: Szymon Janc @ 2010-11-04 10:11 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Szymon Janc
In-Reply-To: <1288865461-3760-1-git-send-email-szymon.janc@tieto.com>

---
 test/simple-oobprovider |   54 +++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 54 insertions(+), 0 deletions(-)
 create mode 100755 test/simple-oobprovider

diff --git a/test/simple-oobprovider b/test/simple-oobprovider
new file mode 100755
index 0000000..135f0f7
--- /dev/null
+++ b/test/simple-oobprovider
@@ -0,0 +1,54 @@
+#!/usr/bin/python
+# Copyright (C) 2010  ST-Ericsson SA
+# Author: Szymon Janc <szymon.janc@tieto.com> for ST-Ericsson
+
+import gobject
+
+import sys
+import dbus
+import dbus.service
+import dbus.mainloop.glib
+
+class Provider(dbus.service.Object):
+
+	remotedata = None
+
+	@dbus.service.method("org.bluez.OOB",
+					in_signature="s", out_signature="ayay")
+
+	def RequestRemoteOobData(self, address):
+		print "RequestRemoteOobData for %s" % (address)
+		return self.remotedata
+
+if __name__ == '__main__':
+	dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
+
+	bus = dbus.SystemBus()
+
+	manager = dbus.Interface(bus.get_object("org.bluez", "/"),
+			"org.bluez.Manager")
+	adapter = dbus.Interface(bus.get_object("org.bluez",
+			manager.DefaultAdapter()), "org.bluez.Adapter")
+	adr = adapter.GetProperties()['Address']
+
+	oob = dbus.Interface(bus.get_object("org.bluez", "/org/bluez"),
+			"org.bluez.OOB")
+
+	path = "/test/oobprovider"
+	provider = Provider(bus, path)
+
+	mainloop = gobject.MainLoop()
+
+	oob.RegisterProvider(path)
+
+	print "Local data for %s:" % (adr)
+	print oob.UpdateLocalOobData(adr)
+
+	provider.remotedata = input("Provide remote data (in python syntax):\n")
+
+	print "You may try pairing now"
+
+	mainloop.run()
+
+	#adapter.UnregisterProvider(path)
+	#print "Provider unregistered"
-- 
1.7.1


^ permalink raw reply related

* [PATCH] Fix status problem after pulling empty call history
From: Rafal Michalski @ 2010-11-04 11:58 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Rafal Michalski

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(-)

diff --git a/plugins/pbap.c b/plugins/pbap.c
index 3ea7d6b..a40563c 100644
--- a/plugins/pbap.c
+++ b/plugins/pbap.c
@@ -251,7 +251,7 @@ static void query_result(const char *buffer, size_t bufsize, int vcards,
 
 	DBG("");
 
-	if (vcards < 0) {
+	if (vcards <= 0) {
 		obex_object_set_io_flags(pbap, G_IO_ERR, -ENOENT);
 		return;
 	}
-- 
1.6.3.3


^ permalink raw reply related

* Re: [PATCH v2] Add support for sending large PBAP response in many parts
From: Luiz Augusto von Dentz @ 2010-11-04 12:20 UTC (permalink / raw)
  To: Radoslaw Jablonski; +Cc: linux-bluetooth
In-Reply-To: <1288860932-9513-2-git-send-email-ext-jablonski.radoslaw@nokia.com>

Hi,

On Thu, Nov 4, 2010 at 10:55 AM, Radoslaw Jablonski
<ext-jablonski.radoslaw@nokia.com> wrote:
> 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 |   82 +++++++++++++++++++++++++++++++++++++++++++++++++-------
>  1 files changed, 72 insertions(+), 10 deletions(-)
>
> diff --git a/plugins/pbap.c b/plugins/pbap.c
> index 3ea7d6b..e59ce8d 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,13 +262,28 @@ 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) {
> +               /* 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;
> +       }

When checking if fd is valid doing < 0

> +
> +       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);

When closing the fd set it to -1.

>        obex_object_set_io_flags(pbap, G_IO_IN, 0);
> +       DBG("Query result end...");
>  }
>
>  static void cache_entry_notify(const char *id, uint32_t handle,
> @@ -829,6 +850,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) {
> +               pbap->fbuf_r = open(pbap->buf_path, 0);
> +
> +               if(pbap->fbuf_r < 0)
> +                       return -EPERM;
> +       }

Again use negative values to check if fd was already opened.

> +       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 +879,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->fbuf_w && !pbap->buffer)
> +               /* No response in buffers now */
>                return -EAGAIN;

Again use negative values.

> -       /* 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 +941,20 @@ static int vobject_close(void *object)
>                pbap->buffer = NULL;
>        }
>
> +       if (pbap->fbuf_r)
> +               close(pbap->fbuf_r);
> +
> +       if (pbap->fbuf_w)
> +               close(pbap->fbuf_w);

When you close a fd reset it to -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;
>  }


-- 
Luiz Augusto von Dentz
Computer Engineer

^ permalink raw reply

* HDP stress test script
From: Elvis Pfützenreuter @ 2010-11-04 12:59 UTC (permalink / raw)
  To: Jose Antonio Santos Cadenas; +Cc: linux-bluetooth

I put together a kind of "stress test" or "torture" script for HDP profile and API. It is available at http://gitorious.org/hdpy project, path is scripts/bluez/hdp_stress_test. Major features:

a) useful either as a test tool and as an API usage example (though scripts/bluez/hdp_oxi_sink is probably a better example);

b) any number of machines can participate (minimum 2, tested with 3);

c) each machine finds the others semi-automatically (tries to contact paired devices that publish an HDP record).

I could extract a segfault with it already, but did not have time to pinpoint the cause. It happened when there were a couple of async Echo's pending and script was killed (which triggers HealthApplication destruction).

Note: it uses the 'Application' property of HealthChannel, which is pending acceptance. This can be easily disabled by changing a flag in script.

Another thing I stumbled on, was the UUIDs property of Device object. The script creates sources and sinks, but 'UUIDs' only shows the sink (0x1402). For now, the script assumes that every source is also a sink in order to find the counterparts, but this needs to be truly fixed in near future.

^ permalink raw reply

* [PATCH] Fix add disconnect watch in connecting state
From: Daniel Örstadius @ 2010-11-04 13:20 UTC (permalink / raw)
  To: linux-bluetooth

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



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

From f705532320bdfb47a06df72c6d031ca096834a3a Mon Sep 17 00:00:00 2001
From: Daniel Orstadius <daniel.orstadius@nokia.com>
Date: Wed, 3 Nov 2010 14:12:29 +0200
Subject: [PATCH] Fix add disconnect watch in connecting state

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);
 
-- 
1.6.0.4


^ 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

* [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

* 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 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 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

* 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 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 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

* [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

* [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] 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] 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

* 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

* 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] 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] 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 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] 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 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 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


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