All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/6] Implement Find by Type request encode/decoding
@ 2010-11-17 18:09 Claudio Takahasi
  2010-11-17 18:09 ` [PATCH 2/6] Add Find By Type Value Response encoding/decoding functions Claudio Takahasi
                   ` (5 more replies)
  0 siblings, 6 replies; 13+ messages in thread
From: Claudio Takahasi @ 2010-11-17 18:09 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Bruna Moreira

From: Bruna Moreira <bruna.moreira@openbossa.org>

---
 attrib/att.c |   72 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 attrib/att.h |    4 ++-
 2 files changed, 73 insertions(+), 3 deletions(-)

diff --git a/attrib/att.c b/attrib/att.c
index fe41d0e..6c889f2 100644
--- a/attrib/att.c
+++ b/attrib/att.c
@@ -198,9 +198,77 @@ struct att_data_list *dec_read_by_grp_resp(const 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)
+			const uint8_t *value, int vlen, uint8_t *pdu, int len)
+{
+	uint16_t min_len = sizeof(pdu[0]) + sizeof(start) + sizeof(end) +
+							sizeof(uint16_t);
+
+	if (pdu == NULL)
+		return 0;
+
+	if (!uuid)
+		return 0;
+
+	if (uuid->type != SDP_UUID16)
+		return 0;
+
+	if (len < min_len)
+		return 0;
+
+	if (vlen > len - min_len)
+		vlen = len - min_len;
+
+	pdu[0] = ATT_OP_FIND_BY_TYPE_REQ;
+	att_put_u16(start, &pdu[1]);
+	att_put_u16(end, &pdu[3]);
+	att_put_u16(uuid->value.uuid16, &pdu[5]);
+
+	if (vlen > 0) {
+		memcpy(&pdu[7], value, vlen);
+		return min_len + vlen;
+	}
+
+	return min_len;
+}
+
+uint16_t dec_find_by_type_req(const uint8_t *pdu, int len, uint16_t *start,
+			uint16_t *end, uuid_t *uuid, uint8_t *value, int *vlen)
 {
-	return 0;
+	int valuelen;
+	uint16_t min_len = sizeof(pdu[0]) + sizeof(*start) +
+						sizeof(*end) + sizeof(uint16_t);
+
+	if (pdu == NULL)
+		return 0;
+
+	if (len < min_len)
+		return 0;
+
+	if (pdu[0] != ATT_OP_FIND_BY_TYPE_REQ)
+		return 0;
+
+	/* First requested handle number */
+	if (start)
+		*start = att_get_u16(&pdu[1]);
+
+	/* Last requested handle number */
+	if (end)
+		*end = att_get_u16(&pdu[3]);
+
+	/* Always UUID16 */
+	if (uuid)
+		sdp_uuid16_create(uuid, att_get_u16(&pdu[5]));
+
+	valuelen = len - min_len;
+
+	/* Attribute value to find */
+	if (valuelen > 0 && value)
+		memcpy(value, pdu + min_len, valuelen);
+
+	if (vlen)
+		*vlen = valuelen;
+
+	return len;
 }
 
 uint16_t enc_read_by_type_req(uint16_t start, uint16_t end, uuid_t *uuid,
diff --git a/attrib/att.h b/attrib/att.h
index ea49dc2..9de338d 100644
--- a/attrib/att.h
+++ b/attrib/att.h
@@ -165,7 +165,9 @@ 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);
+			const uint8_t *value, int vlen, uint8_t *pdu, int len);
+uint16_t dec_find_by_type_req(const uint8_t *pdu, int len, uint16_t *start,
+		uint16_t *end, uuid_t *uuid, uint8_t *value, int *vlen);
 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);
-- 
1.7.3.2


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 2/6] Add Find By Type Value Response encoding/decoding functions
  2010-11-17 18:09 [PATCH 1/6] Implement Find by Type request encode/decoding Claudio Takahasi
@ 2010-11-17 18:09 ` Claudio Takahasi
  2010-11-18 14:47   ` Johan Hedberg
  2010-11-17 18:09 ` [PATCH 3/6] Implement Find by Type Value Request in the atttribute server Claudio Takahasi
                   ` (4 subsequent siblings)
  5 siblings, 1 reply; 13+ messages in thread
From: Claudio Takahasi @ 2010-11-17 18:09 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Claudio Takahasi

Find by type operation is used by Discover Primary Service by Service
UUID. Find By Type Value Response shall contain one or more group handles.
---
 attrib/att.c |   46 ++++++++++++++++++++++++++++++++++++++++++++++
 attrib/att.h |    7 +++++++
 2 files changed, 53 insertions(+), 0 deletions(-)

diff --git a/attrib/att.c b/attrib/att.c
index 6c889f2..60fc74b 100644
--- a/attrib/att.c
+++ b/attrib/att.c
@@ -30,6 +30,8 @@
 #include <bluetooth/sdp.h>
 #include <bluetooth/sdp_lib.h>
 
+#include <glib.h>
+
 #include "att.h"
 
 const char *att_ecode2str(uint8_t status)
@@ -271,6 +273,50 @@ uint16_t dec_find_by_type_req(const uint8_t *pdu, int len, uint16_t *start,
 	return len;
 }
 
+uint16_t enc_find_by_type_resp(GSList *matches, uint8_t *pdu, int len)
+{
+	GSList *l;
+	uint16_t offset;
+
+	if (pdu == NULL || len < 5)
+		return 0;
+
+	pdu[0] = ATT_OP_FIND_BY_TYPE_RESP;
+
+	for (l = matches, offset = 1; l && len >= (offset + 4);
+					l = l->next, offset += 4) {
+		struct range *range = l->data;
+
+		att_put_u16(range->start, &pdu[offset]);
+		att_put_u16(range->end, &pdu[offset + 2]);
+	}
+
+	return offset;
+}
+
+GSList *dec_find_by_type_resp(const uint8_t *pdu, int len)
+{
+	struct range *range;
+	GSList *matches;
+	int offset;
+
+	if (pdu == NULL || len < 5)
+		return NULL;
+
+	if (pdu[0] != ATT_OP_FIND_BY_TYPE_RESP)
+		return NULL;
+
+	for (offset = 1, matches = NULL; len >= (offset + 4); offset += 4) {
+		range = malloc(sizeof(struct range));
+		range->start = att_get_u16(&pdu[offset]);
+		range->end = att_get_u16(&pdu[offset + 2]);
+
+		matches = g_slist_append(matches, range);
+	}
+
+	return matches;
+}
+
 uint16_t enc_read_by_type_req(uint16_t start, uint16_t end, uuid_t *uuid,
 							uint8_t *pdu, int len)
 {
diff --git a/attrib/att.h b/attrib/att.h
index 9de338d..c7260ff 100644
--- a/attrib/att.h
+++ b/attrib/att.h
@@ -122,6 +122,11 @@ struct att_data_list {
 	uint8_t **data;
 };
 
+struct range {
+	uint16_t start;
+	uint16_t end;
+};
+
 /* These functions do byte conversion */
 static inline uint8_t att_get_u8(const void *ptr)
 {
@@ -168,6 +173,8 @@ uint16_t enc_find_by_type_req(uint16_t start, uint16_t end, uuid_t *uuid,
 			const uint8_t *value, int vlen, uint8_t *pdu, int len);
 uint16_t dec_find_by_type_req(const uint8_t *pdu, int len, uint16_t *start,
 		uint16_t *end, uuid_t *uuid, uint8_t *value, int *vlen);
+uint16_t enc_find_by_type_resp(GSList *ranges, uint8_t *pdu, int len);
+GSList *dec_find_by_type_resp(const 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);
-- 
1.7.3.2


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 3/6] Implement Find by Type Value Request in the atttribute server
  2010-11-17 18:09 [PATCH 1/6] Implement Find by Type request encode/decoding Claudio Takahasi
  2010-11-17 18:09 ` [PATCH 2/6] Add Find By Type Value Response encoding/decoding functions Claudio Takahasi
@ 2010-11-17 18:09 ` Claudio Takahasi
  2010-11-18 18:02   ` [PATCH v2 " Claudio Takahasi
  2010-11-17 18:09 ` [PATCH 4/6] Extend bt_string2uuid to convert hex strings to UUID16 Claudio Takahasi
                   ` (3 subsequent siblings)
  5 siblings, 1 reply; 13+ messages in thread
From: Claudio Takahasi @ 2010-11-17 18:09 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Claudio Takahasi

GATT Discover Primary Service by Service UUID sub-procedure is based
on ATT Find By Type Value Request/Response.

Implement an extra verification for broken requests: "Ending Handle"
different than 0xFFFF. The Group End Handle may be greater than the
"Ending Handle" in the Find By Type Value Request. Forces the "Ending
Handle" in the response to 0xFFFF to avoid another request from the
clients. 0xFFFF means that the sub-procedure is complete.
---
 src/attrib-server.c |   80 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 80 insertions(+), 0 deletions(-)

diff --git a/src/attrib-server.c b/src/attrib-server.c
index 375b731..05a0fb7 100644
--- a/src/attrib-server.c
+++ b/src/attrib-server.c
@@ -383,6 +383,76 @@ static int find_info(uint16_t start, uint16_t end, uint8_t *pdu, int len)
 	return length;
 }
 
+static int find_by_type(uint16_t start, uint16_t end, uuid_t *uuid,
+			const uint8_t *value, int vlen, uint8_t *opdu, int mtu)
+{
+	struct attribute *a;
+	struct range *range;
+	GSList *l, *matches;
+	int len;
+
+	if (start > end || start == 0x0000)
+		return enc_error_resp(ATT_OP_FIND_BY_TYPE_REQ, start,
+					ATT_ECODE_INVALID_HANDLE, opdu, mtu);
+
+	/* Searching first requested handle number */
+	for (l = database, matches = NULL, range = NULL; l; l = l->next) {
+		a = l->data;
+
+		if (a->handle < start)
+			continue;
+
+		if (a->handle > end)
+			break;
+
+		/* Primary service? Attribute value matches? */
+		if ((sdp_uuid_cmp(&a->uuid, uuid) == 0) && (a->len == vlen) &&
+					(memcmp(a->data, value, vlen) == 0)) {
+
+			range = g_new0(struct range, 1);
+			range->start = a->handle;
+
+			matches = g_slist_append(matches, range);
+		} else if (range) {
+			/*
+			 * Update the last found handle or reset the pointer
+			 * to track that a new group started: Primary or
+			 * Secondary service.
+			 */
+			if (sdp_uuid_cmp(&a->uuid, &prim_uuid) == 0 ||
+					sdp_uuid_cmp(&a->uuid, &snd_uuid) == 0)
+				range = NULL;
+			else
+				range->end = a->handle;
+		}
+	}
+
+	if (range) {
+		if (l == NULL) {
+			/* Avoids another iteration */
+			range->end = 0xFFFF;
+		} else if (range->end == 0) {
+			/*
+			 * Broken requests: requested End Handle is not 0xFFFF.
+			 * Given handle is in the middle of a service definition.
+			 */
+			matches = g_slist_remove(matches, range);
+			g_free(range);
+		}
+	}
+
+	if (matches == NULL)
+		return enc_error_resp(ATT_OP_FIND_BY_TYPE_REQ, start,
+				ATT_ECODE_ATTR_NOT_FOUND, opdu, mtu);
+
+	len = enc_find_by_type_resp(matches, opdu, mtu);
+
+	g_slist_foreach(matches, (GFunc) g_free, NULL);
+	g_slist_free(matches);
+
+	return len;
+}
+
 static int handle_cmp(gconstpointer a, gconstpointer b)
 {
 	const struct attribute *attrib = a;
@@ -522,6 +592,16 @@ static void channel_handler(const uint8_t *ipdu, uint16_t len,
 			write_value(start, value, vlen);
 		return;
 	case ATT_OP_FIND_BY_TYPE_REQ:
+		length = dec_find_by_type_req(ipdu, len, &start, &end,
+							&uuid, value, &vlen);
+		if (length == 0) {
+			status = ATT_ECODE_INVALID_PDU;
+			goto done;
+		}
+
+		length = find_by_type(start, end, &uuid, value, vlen,
+							opdu, channel->mtu);
+		break;
 	case ATT_OP_READ_BLOB_REQ:
 	case ATT_OP_READ_MULTI_REQ:
 	case ATT_OP_PREP_WRITE_REQ:
-- 
1.7.3.2


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 4/6] Extend bt_string2uuid to convert hex strings to UUID16
  2010-11-17 18:09 [PATCH 1/6] Implement Find by Type request encode/decoding Claudio Takahasi
  2010-11-17 18:09 ` [PATCH 2/6] Add Find By Type Value Response encoding/decoding functions Claudio Takahasi
  2010-11-17 18:09 ` [PATCH 3/6] Implement Find by Type Value Request in the atttribute server Claudio Takahasi
@ 2010-11-17 18:09 ` Claudio Takahasi
  2010-11-17 18:09 ` [PATCH 5/6] Add an extra parameter in the discovery primary to specify the UUID Claudio Takahasi
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 13+ messages in thread
From: Claudio Takahasi @ 2010-11-17 18:09 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Claudio Takahasi

Convert four or six(0x) digits length hexadecimal strings to UUID16.
---
 src/glib-helper.c |   22 ++++++++++++++++++++--
 1 files changed, 20 insertions(+), 2 deletions(-)

diff --git a/src/glib-helper.c b/src/glib-helper.c
index 9d76626..232fc71 100644
--- a/src/glib-helper.c
+++ b/src/glib-helper.c
@@ -466,6 +466,24 @@ static inline gboolean is_uuid128(const char *string)
 			string[23] == '-');
 }
 
+static int string2uuid16(uuid_t *uuid, const char *string)
+{
+	int length = strlen(string);
+	char *endptr = NULL;
+	uint16_t u16;
+
+	if (length != 4 && length != 6)
+		return -EINVAL;
+
+	u16 = strtol(string, &endptr, 16);
+	if (endptr && *endptr == '\0') {
+		sdp_uuid16_create(uuid, u16);
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
 char *bt_name2string(const char *pattern)
 {
 	uuid_t uuid;
@@ -529,9 +547,9 @@ int bt_string2uuid(uuid_t *uuid, const char *string)
 			sdp_uuid16_create(uuid, class);
 			return 0;
 		}
-	}
 
-	return -1;
+		return string2uuid16(uuid, string);
+	}
 }
 
 gchar *bt_list2string(GSList *list)
-- 
1.7.3.2


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 5/6] Add an extra parameter in the discovery primary to specify the UUID
  2010-11-17 18:09 [PATCH 1/6] Implement Find by Type request encode/decoding Claudio Takahasi
                   ` (2 preceding siblings ...)
  2010-11-17 18:09 ` [PATCH 4/6] Extend bt_string2uuid to convert hex strings to UUID16 Claudio Takahasi
@ 2010-11-17 18:09 ` Claudio Takahasi
  2010-11-17 18:09 ` [PATCH 6/6] Implement Discover Primary Service by Service UUID in the gatttool Claudio Takahasi
  2010-11-18 14:45 ` [PATCH 1/6] Implement Find by Type request encode/decoding Johan Hedberg
  5 siblings, 0 replies; 13+ messages in thread
From: Claudio Takahasi @ 2010-11-17 18:09 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Claudio Takahasi

Extends discover primary function to perform discover by UUID. UUID
parameter defines which procedure will be executed: Discover All
Primary Services or Discover Primary Service by Service UUID.
---
 attrib/client.c   |    8 ++++----
 attrib/gatt.c     |   37 ++++++++++++++++++++++++++++++-------
 attrib/gatt.h     |    4 ++--
 attrib/gatttool.c |    6 ++++--
 4 files changed, 40 insertions(+), 15 deletions(-)

diff --git a/attrib/client.c b/attrib/client.c
index 955e623..a851a74 100644
--- a/attrib/client.c
+++ b/attrib/client.c
@@ -363,8 +363,8 @@ static void connect_cb(GIOChannel *chan, GError *gerr, gpointer user_data)
 		return;
 	}
 
-	atid = gatt_discover_primary(gatt->attrib, 0x0001, 0xffff, primary_cb,
-									gatt);
+	atid = gatt_discover_primary(gatt->attrib, 0x0001, 0xffff, NULL,
+							primary_cb, gatt);
 	if (atid == 0)
 		goto fail;
 
@@ -1311,8 +1311,8 @@ static void primary_cb(guint8 status, const guint8 *pdu, guint16 plen,
 	 * the Error Code is set to Attribute Not Found.
 	 */
 	gatt->attrib = g_attrib_ref(gatt->attrib);
-	gatt->atid = gatt_discover_primary(gatt->attrib,
-				end + 1, 0xffff, primary_cb, gatt);
+	gatt->atid = gatt_discover_primary(gatt->attrib, end + 1, 0xffff, NULL,
+							primary_cb, gatt);
 done:
 	g_attrib_unref(gatt->attrib);
 }
diff --git a/attrib/gatt.c b/attrib/gatt.c
index 24ec990..2c87daf 100644
--- a/attrib/gatt.c
+++ b/attrib/gatt.c
@@ -31,21 +31,44 @@
 #include "gattrib.h"
 #include "gatt.h"
 
-guint gatt_discover_primary(GAttrib *attrib, uint16_t start,
-		uint16_t end, GAttribResultFunc func, gpointer user_data)
+guint gatt_discover_primary(GAttrib *attrib, uint16_t start, uint16_t end,
+		uuid_t *uuid, GAttribResultFunc func, gpointer user_data)
 {
 	uint8_t pdu[ATT_DEFAULT_MTU];
-	uuid_t uuid;
+	uuid_t prim;
 	guint16 plen;
+	uint8_t op;
+
+	sdp_uuid16_create(&prim, GATT_PRIM_SVC_UUID);
+
+	if (uuid == NULL) {
+
+		/* Discover all primary services */
+		op = ATT_OP_READ_BY_GROUP_REQ;
+		plen = enc_read_by_grp_req(start, end, &prim, pdu, sizeof(pdu));
+	} else {
+		const void *value;
+		int vlen;
 
-	sdp_uuid16_create(&uuid, GATT_PRIM_SVC_UUID);
+		/* Discover primary service by service UUID */
+		op = ATT_OP_FIND_BY_TYPE_REQ;
+
+		if (uuid->type == SDP_UUID16) {
+			value = &uuid->value.uuid16;
+			vlen = sizeof(uuid->value.uuid16);
+		} else {
+			value = &uuid->value.uuid128;
+			vlen = sizeof(uuid->value.uuid128);
+		}
+
+		plen = enc_find_by_type_req(start, end, &prim, value, vlen,
+							pdu, sizeof(pdu));
+	}
 
-	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);
+	return g_attrib_send(attrib, op, pdu, plen, func, user_data, NULL);
 }
 
 guint gatt_discover_char(GAttrib *attrib, uint16_t start, uint16_t end,
diff --git a/attrib/gatt.h b/attrib/gatt.h
index f1599c2..4e7d88b 100644
--- a/attrib/gatt.h
+++ b/attrib/gatt.h
@@ -24,8 +24,8 @@
 
 #define GATT_CID 4
 
-guint gatt_discover_primary(GAttrib *attrib, uint16_t start,
-		uint16_t end, GAttribResultFunc func, gpointer user_data);
+guint gatt_discover_primary(GAttrib *attrib, uint16_t start, uint16_t end,
+		uuid_t *uuid, GAttribResultFunc func, gpointer user_data);
 
 guint gatt_discover_char(GAttrib *attrib, uint16_t start, uint16_t end,
 				GAttribResultFunc func, gpointer user_data);
diff --git a/attrib/gatttool.c b/attrib/gatttool.c
index b9f5138..ac9745d 100644
--- a/attrib/gatttool.c
+++ b/attrib/gatttool.c
@@ -191,7 +191,8 @@ static void primary_cb(guint8 status, const guint8 *pdu, guint16 plen,
 	 * Read by Group Type Request until Error Response is received and
 	 * the Error Code is set to Attribute Not Found.
 	 */
-	gatt_discover_primary(attrib, end + 1, opt_end, primary_cb, attrib);
+	gatt_discover_primary(attrib, end + 1, opt_end, NULL, primary_cb,
+								attrib);
 
 	return;
 
@@ -250,7 +251,8 @@ static gboolean primary(gpointer user_data)
 {
 	GAttrib *attrib = user_data;
 
-	gatt_discover_primary(attrib, opt_start, opt_end, primary_cb, attrib);
+	gatt_discover_primary(attrib, opt_start, opt_end, NULL, primary_cb,
+								attrib);
 
 	return FALSE;
 }
-- 
1.7.3.2


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 6/6] Implement Discover Primary Service by Service UUID in the gatttool
  2010-11-17 18:09 [PATCH 1/6] Implement Find by Type request encode/decoding Claudio Takahasi
                   ` (3 preceding siblings ...)
  2010-11-17 18:09 ` [PATCH 5/6] Add an extra parameter in the discovery primary to specify the UUID Claudio Takahasi
@ 2010-11-17 18:09 ` Claudio Takahasi
  2010-11-18 18:07   ` [PATCH v2 " Claudio Takahasi
  2010-11-18 14:45 ` [PATCH 1/6] Implement Find by Type request encode/decoding Johan Hedberg
  5 siblings, 1 reply; 13+ messages in thread
From: Claudio Takahasi @ 2010-11-17 18:09 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Claudio Takahasi

Implement only the first interaction of the discovery procedure. If the
response doesn't fit in the MTU, "start" and "end" options can be used
to discover the handles ranges of the remaining primary service instances.
UUID16 and UUID128 are supported in the uuid option.

Usage example:
$gatttool -i hcix -b xx:xx:xx:xx:xx:xx --uuid=1801 --primary
---
 Makefile.am       |    3 +-
 attrib/gatttool.c |   65 ++++++++++++++++++++++++++++++++++++++++++++++++----
 2 files changed, 62 insertions(+), 6 deletions(-)

diff --git a/Makefile.am b/Makefile.am
index da308a7..1d83943 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -177,7 +177,8 @@ 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/gattrib.c btio/btio.c \
+			  src/glib-helper.h src/glib-helper.c
 attrib_gatttool_LDADD = lib/libbluetooth.la @GLIB_LIBS@
 
 builtin_modules += attrib
diff --git a/attrib/gatttool.c b/attrib/gatttool.c
index ac9745d..61afd52 100644
--- a/attrib/gatttool.c
+++ b/attrib/gatttool.c
@@ -41,6 +41,7 @@
 #include "att.h"
 #include "btio.h"
 #include "gattrib.h"
+#include "glib-helper.h"
 #include "gatt.h"
 
 /* Minimum MTU for L2CAP connections over BR/EDR */
@@ -49,6 +50,7 @@
 static gchar *opt_src = NULL;
 static gchar *opt_dst = NULL;
 static gchar *opt_value = NULL;
+static uuid_t *opt_uuid = NULL;
 static int opt_start = 0x0001;
 static int opt_end = 0xffff;
 static int opt_handle = -1;
@@ -135,7 +137,7 @@ static GIOChannel *do_connect(gboolean le)
 	return chan;
 }
 
-static void primary_cb(guint8 status, const guint8 *pdu, guint16 plen,
+static void primary_all_cb(guint8 status, const guint8 *pdu, guint16 plen,
 							gpointer user_data)
 {
 	GAttrib *attrib = user_data;
@@ -191,9 +193,9 @@ static void primary_cb(guint8 status, const guint8 *pdu, guint16 plen,
 	 * Read by Group Type Request until Error Response is received and
 	 * the Error Code is set to Attribute Not Found.
 	 */
-	gatt_discover_primary(attrib, end + 1, opt_end, NULL, primary_cb,
-								attrib);
 
+	gatt_discover_primary(attrib, end + 1, opt_end, NULL, primary_all_cb,
+								attrib);
 	return;
 
 done:
@@ -201,6 +203,36 @@ done:
 		g_main_loop_quit(event_loop);
 }
 
+static void primary_by_uuid_cb(guint8 status, const guint8 *pdu, guint16 plen,
+							gpointer user_data)
+{
+	GSList *ranges, *l;
+
+	if (status != 0) {
+		g_printerr("Discover primary services by UUID failed: %s\n",
+							att_ecode2str(status));
+		goto done;
+	}
+
+	ranges = dec_find_by_type_resp(pdu, plen);
+	if (ranges == NULL) {
+		g_printerr("Protocol error!\n");
+		goto done;
+	}
+
+	for (l = ranges; l; l = l->next) {
+		struct range *range = l->data;
+		g_print("Starting handle: %04x Ending handle: %04x\n",
+						range->start, range->end);
+	}
+
+	g_slist_foreach(ranges, (GFunc) g_free, NULL);
+	g_slist_free(ranges);
+
+done:
+	g_main_loop_quit(event_loop);
+}
+
 static void events_handler(const uint8_t *pdu, uint16_t len, gpointer user_data)
 {
 	GAttrib *attrib = user_data;
@@ -251,8 +283,12 @@ static gboolean primary(gpointer user_data)
 {
 	GAttrib *attrib = user_data;
 
-	gatt_discover_primary(attrib, opt_start, opt_end, NULL, primary_cb,
-								attrib);
+	if (opt_uuid)
+		gatt_discover_primary(attrib, opt_start, opt_end, opt_uuid,
+						primary_by_uuid_cb, attrib);
+	else
+		gatt_discover_primary(attrib, opt_start, opt_end, NULL,
+						primary_all_cb, attrib);
 
 	return FALSE;
 }
@@ -477,11 +513,29 @@ static gboolean characteristics_desc(gpointer user_data)
 	return FALSE;
 }
 
+static gboolean parse_uuid(const char *key, const char *value,
+				gpointer user_data, GError **error)
+{
+	if (!value)
+		return FALSE;
+
+	opt_uuid = g_try_malloc(sizeof(uuid_t));
+	if (opt_uuid == NULL)
+		return FALSE;
+
+	if (bt_string2uuid(opt_uuid, value) < 0)
+		return FALSE;
+
+	return TRUE;
+}
+
 static GOptionEntry primary_char_options[] = {
 	{ "start", 's' , 0, G_OPTION_ARG_INT, &opt_start,
 		"Starting handle(optional)", "0x0001" },
 	{ "end", 'e' , 0, G_OPTION_ARG_INT, &opt_end,
 		"Ending handle(optional)", "0xffff" },
+	{ "uuid", 'u', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_CALLBACK,
+		parse_uuid, "UUID16 or UUID128(optional)", "0x1801"},
 	{ NULL },
 };
 
@@ -610,6 +664,7 @@ done:
 	g_option_context_free(context);
 	g_free(opt_src);
 	g_free(opt_dst);
+	g_free(opt_uuid);
 
 	if (got_error)
 		exit(EXIT_FAILURE);
-- 
1.7.3.2


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* Re: [PATCH 1/6] Implement Find by Type request encode/decoding
  2010-11-17 18:09 [PATCH 1/6] Implement Find by Type request encode/decoding Claudio Takahasi
                   ` (4 preceding siblings ...)
  2010-11-17 18:09 ` [PATCH 6/6] Implement Discover Primary Service by Service UUID in the gatttool Claudio Takahasi
@ 2010-11-18 14:45 ` Johan Hedberg
  5 siblings, 0 replies; 13+ messages in thread
From: Johan Hedberg @ 2010-11-18 14:45 UTC (permalink / raw)
  To: Claudio Takahasi; +Cc: linux-bluetooth, Bruna Moreira

Hi,

On Wed, Nov 17, 2010, Claudio Takahasi wrote:
> From: Bruna Moreira <bruna.moreira@openbossa.org>
> 
> ---
>  attrib/att.c |   72 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
>  attrib/att.h |    4 ++-
>  2 files changed, 73 insertions(+), 3 deletions(-)

Pushed upstream. Thanks.

Johan

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH 2/6] Add Find By Type Value Response encoding/decoding functions
  2010-11-17 18:09 ` [PATCH 2/6] Add Find By Type Value Response encoding/decoding functions Claudio Takahasi
@ 2010-11-18 14:47   ` Johan Hedberg
  2010-11-18 15:25     ` Claudio Takahasi
  0 siblings, 1 reply; 13+ messages in thread
From: Johan Hedberg @ 2010-11-18 14:47 UTC (permalink / raw)
  To: Claudio Takahasi; +Cc: linux-bluetooth

Hi Claudio,

On Wed, Nov 17, 2010, Claudio Takahasi wrote:
> --- a/attrib/att.h
> +++ b/attrib/att.h
> @@ -122,6 +122,11 @@ struct att_data_list {
>  	uint8_t **data;
>  };
>  
> +struct range {
> +	uint16_t start;
> +	uint16_t end;
> +};
> +

Since this is in the public header file it should be prefixed with att_,
right? (which should also apply for all public symbols here). However,
it seems like you're only using the struct internally in att.c so
probably it doesn't even need to be in the public header file?

Johan

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH 2/6] Add Find By Type Value Response encoding/decoding functions
  2010-11-18 14:47   ` Johan Hedberg
@ 2010-11-18 15:25     ` Claudio Takahasi
  2010-11-18 17:48       ` [PATCH v2 " Claudio Takahasi
  0 siblings, 1 reply; 13+ messages in thread
From: Claudio Takahasi @ 2010-11-18 15:25 UTC (permalink / raw)
  To: Claudio Takahasi, linux-bluetooth

Hi Johan,

On Thu, Nov 18, 2010 at 12:47 PM, Johan Hedberg <johan.hedberg@gmail.com> wrote:
> Hi Claudio,
>
> On Wed, Nov 17, 2010, Claudio Takahasi wrote:
>> --- a/attrib/att.h
>> +++ b/attrib/att.h
>> @@ -122,6 +122,11 @@ struct att_data_list {
>>       uint8_t **data;
>>  };
>>
>> +struct range {
>> +     uint16_t start;
>> +     uint16_t end;
>> +};
>> +
>
> Since this is in the public header file it should be prefixed with att_,
> right? (which should also apply for all public symbols here). However,
> it seems like you're only using the struct internally in att.c so
> probably it doesn't even need to be in the public header file?
>
> Johan
>

It will be used in the gatttool, attribute server and attribute client.
I gonna add the prefix att_ and resend the patches.

Claudio.

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH v2 2/6] Add Find By Type Value Response encoding/decoding functions
  2010-11-18 15:25     ` Claudio Takahasi
@ 2010-11-18 17:48       ` Claudio Takahasi
  2010-11-18 20:01         ` Johan Hedberg
  0 siblings, 1 reply; 13+ messages in thread
From: Claudio Takahasi @ 2010-11-18 17:48 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Claudio Takahasi

Find by type operation is used by Discover Primary Service by Service
UUID. Find By Type Value Response shall contain one or more group handles.
---
 attrib/att.c |   46 ++++++++++++++++++++++++++++++++++++++++++++++
 attrib/att.h |    7 +++++++
 2 files changed, 53 insertions(+), 0 deletions(-)

diff --git a/attrib/att.c b/attrib/att.c
index 6c889f2..8655e5e 100644
--- a/attrib/att.c
+++ b/attrib/att.c
@@ -30,6 +30,8 @@
 #include <bluetooth/sdp.h>
 #include <bluetooth/sdp_lib.h>
 
+#include <glib.h>
+
 #include "att.h"
 
 const char *att_ecode2str(uint8_t status)
@@ -271,6 +273,50 @@ uint16_t dec_find_by_type_req(const uint8_t *pdu, int len, uint16_t *start,
 	return len;
 }
 
+uint16_t enc_find_by_type_resp(GSList *matches, uint8_t *pdu, int len)
+{
+	GSList *l;
+	uint16_t offset;
+
+	if (pdu == NULL || len < 5)
+		return 0;
+
+	pdu[0] = ATT_OP_FIND_BY_TYPE_RESP;
+
+	for (l = matches, offset = 1; l && len >= (offset + 4);
+					l = l->next, offset += 4) {
+		struct att_range *range = l->data;
+
+		att_put_u16(range->start, &pdu[offset]);
+		att_put_u16(range->end, &pdu[offset + 2]);
+	}
+
+	return offset;
+}
+
+GSList *dec_find_by_type_resp(const uint8_t *pdu, int len)
+{
+	struct att_range *range;
+	GSList *matches;
+	int offset;
+
+	if (pdu == NULL || len < 5)
+		return NULL;
+
+	if (pdu[0] != ATT_OP_FIND_BY_TYPE_RESP)
+		return NULL;
+
+	for (offset = 1, matches = NULL; len >= (offset + 4); offset += 4) {
+		range = malloc(sizeof(struct att_range));
+		range->start = att_get_u16(&pdu[offset]);
+		range->end = att_get_u16(&pdu[offset + 2]);
+
+		matches = g_slist_append(matches, range);
+	}
+
+	return matches;
+}
+
 uint16_t enc_read_by_type_req(uint16_t start, uint16_t end, uuid_t *uuid,
 							uint8_t *pdu, int len)
 {
diff --git a/attrib/att.h b/attrib/att.h
index 9de338d..7c98b4a 100644
--- a/attrib/att.h
+++ b/attrib/att.h
@@ -122,6 +122,11 @@ struct att_data_list {
 	uint8_t **data;
 };
 
+struct att_range {
+	uint16_t start;
+	uint16_t end;
+};
+
 /* These functions do byte conversion */
 static inline uint8_t att_get_u8(const void *ptr)
 {
@@ -168,6 +173,8 @@ uint16_t enc_find_by_type_req(uint16_t start, uint16_t end, uuid_t *uuid,
 			const uint8_t *value, int vlen, uint8_t *pdu, int len);
 uint16_t dec_find_by_type_req(const uint8_t *pdu, int len, uint16_t *start,
 		uint16_t *end, uuid_t *uuid, uint8_t *value, int *vlen);
+uint16_t enc_find_by_type_resp(GSList *ranges, uint8_t *pdu, int len);
+GSList *dec_find_by_type_resp(const 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);
-- 
1.7.3.2


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH v2 3/6] Implement Find by Type Value Request in the atttribute server
  2010-11-17 18:09 ` [PATCH 3/6] Implement Find by Type Value Request in the atttribute server Claudio Takahasi
@ 2010-11-18 18:02   ` Claudio Takahasi
  0 siblings, 0 replies; 13+ messages in thread
From: Claudio Takahasi @ 2010-11-18 18:02 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Claudio Takahasi

GATT Discover Primary Service by Service UUID sub-procedure is based
on ATT Find By Type Value Request/Response.

Implement an extra verification for broken requests: "Ending Handle"
different than 0xFFFF. The Group End Handle may be greater than the
"Ending Handle" in the Find By Type Value Request. Forces the "Ending
Handle" in the response to 0xFFFF to avoid another request from the
clients. 0xFFFF means that the sub-procedure is complete.
---
 src/attrib-server.c |   80 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 80 insertions(+), 0 deletions(-)

diff --git a/src/attrib-server.c b/src/attrib-server.c
index 375b731..41c0ffc 100644
--- a/src/attrib-server.c
+++ b/src/attrib-server.c
@@ -383,6 +383,76 @@ static int find_info(uint16_t start, uint16_t end, uint8_t *pdu, int len)
 	return length;
 }
 
+static int find_by_type(uint16_t start, uint16_t end, uuid_t *uuid,
+			const uint8_t *value, int vlen, uint8_t *opdu, int mtu)
+{
+	struct attribute *a;
+	struct att_range *range;
+	GSList *l, *matches;
+	int len;
+
+	if (start > end || start == 0x0000)
+		return enc_error_resp(ATT_OP_FIND_BY_TYPE_REQ, start,
+					ATT_ECODE_INVALID_HANDLE, opdu, mtu);
+
+	/* Searching first requested handle number */
+	for (l = database, matches = NULL, range = NULL; l; l = l->next) {
+		a = l->data;
+
+		if (a->handle < start)
+			continue;
+
+		if (a->handle > end)
+			break;
+
+		/* Primary service? Attribute value matches? */
+		if ((sdp_uuid_cmp(&a->uuid, uuid) == 0) && (a->len == vlen) &&
+					(memcmp(a->data, value, vlen) == 0)) {
+
+			range = g_new0(struct att_range, 1);
+			range->start = a->handle;
+
+			matches = g_slist_append(matches, range);
+		} else if (range) {
+			/*
+			 * Update the last found handle or reset the pointer
+			 * to track that a new group started: Primary or
+			 * Secondary service.
+			 */
+			if (sdp_uuid_cmp(&a->uuid, &prim_uuid) == 0 ||
+					sdp_uuid_cmp(&a->uuid, &snd_uuid) == 0)
+				range = NULL;
+			else
+				range->end = a->handle;
+		}
+	}
+
+	if (range) {
+		if (l == NULL) {
+			/* Avoids another iteration */
+			range->end = 0xFFFF;
+		} else if (range->end == 0) {
+			/*
+			 * Broken requests: requested End Handle is not 0xFFFF.
+			 * Given handle is in the middle of a service definition.
+			 */
+			matches = g_slist_remove(matches, range);
+			g_free(range);
+		}
+	}
+
+	if (matches == NULL)
+		return enc_error_resp(ATT_OP_FIND_BY_TYPE_REQ, start,
+				ATT_ECODE_ATTR_NOT_FOUND, opdu, mtu);
+
+	len = enc_find_by_type_resp(matches, opdu, mtu);
+
+	g_slist_foreach(matches, (GFunc) g_free, NULL);
+	g_slist_free(matches);
+
+	return len;
+}
+
 static int handle_cmp(gconstpointer a, gconstpointer b)
 {
 	const struct attribute *attrib = a;
@@ -522,6 +592,16 @@ static void channel_handler(const uint8_t *ipdu, uint16_t len,
 			write_value(start, value, vlen);
 		return;
 	case ATT_OP_FIND_BY_TYPE_REQ:
+		length = dec_find_by_type_req(ipdu, len, &start, &end,
+							&uuid, value, &vlen);
+		if (length == 0) {
+			status = ATT_ECODE_INVALID_PDU;
+			goto done;
+		}
+
+		length = find_by_type(start, end, &uuid, value, vlen,
+							opdu, channel->mtu);
+		break;
 	case ATT_OP_READ_BLOB_REQ:
 	case ATT_OP_READ_MULTI_REQ:
 	case ATT_OP_PREP_WRITE_REQ:
-- 
1.7.3.2


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH v2 6/6] Implement Discover Primary Service by Service UUID in the gatttool
  2010-11-17 18:09 ` [PATCH 6/6] Implement Discover Primary Service by Service UUID in the gatttool Claudio Takahasi
@ 2010-11-18 18:07   ` Claudio Takahasi
  0 siblings, 0 replies; 13+ messages in thread
From: Claudio Takahasi @ 2010-11-18 18:07 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Claudio Takahasi

Implement only the first interaction of the discovery procedure. If the
response doesn't fit in the MTU, "start" and "end" options can be used
to discover the handles ranges of the remaining primary service instances.
UUID16 and UUID128 are supported in the uuid option.

Usage example:
$gatttool -i hcix -b xx:xx:xx:xx:xx:xx --uuid=1801 --primary
---
 Makefile.am       |    3 +-
 attrib/gatttool.c |   65 ++++++++++++++++++++++++++++++++++++++++++++++++----
 2 files changed, 62 insertions(+), 6 deletions(-)

diff --git a/Makefile.am b/Makefile.am
index 03a9bf2..5f96975 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -178,7 +178,8 @@ 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/gattrib.c btio/btio.c \
+			  src/glib-helper.h src/glib-helper.c
 attrib_gatttool_LDADD = lib/libbluetooth.la @GLIB_LIBS@
 
 builtin_modules += attrib
diff --git a/attrib/gatttool.c b/attrib/gatttool.c
index 1a74edd..e961431 100644
--- a/attrib/gatttool.c
+++ b/attrib/gatttool.c
@@ -41,6 +41,7 @@
 #include "att.h"
 #include "btio.h"
 #include "gattrib.h"
+#include "glib-helper.h"
 #include "gatt.h"
 
 /* Minimum MTU for L2CAP connections over BR/EDR */
@@ -50,6 +51,7 @@ static gchar *opt_src = NULL;
 static gchar *opt_dst = NULL;
 static gchar *opt_value = NULL;
 static gchar *opt_sec_level = "low";
+static uuid_t *opt_uuid = NULL;
 static int opt_start = 0x0001;
 static int opt_end = 0xffff;
 static int opt_handle = -1;
@@ -144,7 +146,7 @@ static GIOChannel *do_connect(gboolean le)
 	return chan;
 }
 
-static void primary_cb(guint8 status, const guint8 *pdu, guint16 plen,
+static void primary_all_cb(guint8 status, const guint8 *pdu, guint16 plen,
 							gpointer user_data)
 {
 	GAttrib *attrib = user_data;
@@ -200,9 +202,9 @@ static void primary_cb(guint8 status, const guint8 *pdu, guint16 plen,
 	 * Read by Group Type Request until Error Response is received and
 	 * the Error Code is set to Attribute Not Found.
 	 */
-	gatt_discover_primary(attrib, end + 1, opt_end, NULL, primary_cb,
-								attrib);
 
+	gatt_discover_primary(attrib, end + 1, opt_end, NULL, primary_all_cb,
+								attrib);
 	return;
 
 done:
@@ -210,6 +212,36 @@ done:
 		g_main_loop_quit(event_loop);
 }
 
+static void primary_by_uuid_cb(guint8 status, const guint8 *pdu, guint16 plen,
+							gpointer user_data)
+{
+	GSList *ranges, *l;
+
+	if (status != 0) {
+		g_printerr("Discover primary services by UUID failed: %s\n",
+							att_ecode2str(status));
+		goto done;
+	}
+
+	ranges = dec_find_by_type_resp(pdu, plen);
+	if (ranges == NULL) {
+		g_printerr("Protocol error!\n");
+		goto done;
+	}
+
+	for (l = ranges; l; l = l->next) {
+		struct att_range *range = l->data;
+		g_print("Starting handle: %04x Ending handle: %04x\n",
+						range->start, range->end);
+	}
+
+	g_slist_foreach(ranges, (GFunc) g_free, NULL);
+	g_slist_free(ranges);
+
+done:
+	g_main_loop_quit(event_loop);
+}
+
 static void events_handler(const uint8_t *pdu, uint16_t len, gpointer user_data)
 {
 	GAttrib *attrib = user_data;
@@ -260,8 +292,12 @@ static gboolean primary(gpointer user_data)
 {
 	GAttrib *attrib = user_data;
 
-	gatt_discover_primary(attrib, opt_start, opt_end, NULL, primary_cb,
-								attrib);
+	if (opt_uuid)
+		gatt_discover_primary(attrib, opt_start, opt_end, opt_uuid,
+						primary_by_uuid_cb, attrib);
+	else
+		gatt_discover_primary(attrib, opt_start, opt_end, NULL,
+						primary_all_cb, attrib);
 
 	return FALSE;
 }
@@ -486,11 +522,29 @@ static gboolean characteristics_desc(gpointer user_data)
 	return FALSE;
 }
 
+static gboolean parse_uuid(const char *key, const char *value,
+				gpointer user_data, GError **error)
+{
+	if (!value)
+		return FALSE;
+
+	opt_uuid = g_try_malloc(sizeof(uuid_t));
+	if (opt_uuid == NULL)
+		return FALSE;
+
+	if (bt_string2uuid(opt_uuid, value) < 0)
+		return FALSE;
+
+	return TRUE;
+}
+
 static GOptionEntry primary_char_options[] = {
 	{ "start", 's' , 0, G_OPTION_ARG_INT, &opt_start,
 		"Starting handle(optional)", "0x0001" },
 	{ "end", 'e' , 0, G_OPTION_ARG_INT, &opt_end,
 		"Ending handle(optional)", "0xffff" },
+	{ "uuid", 'u', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_CALLBACK,
+		parse_uuid, "UUID16 or UUID128(optional)", "0x1801"},
 	{ NULL },
 };
 
@@ -621,6 +675,7 @@ done:
 	g_option_context_free(context);
 	g_free(opt_src);
 	g_free(opt_dst);
+	g_free(opt_uuid);
 
 	if (got_error)
 		exit(EXIT_FAILURE);
-- 
1.7.3.2


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* Re: [PATCH v2 2/6] Add Find By Type Value Response encoding/decoding functions
  2010-11-18 17:48       ` [PATCH v2 " Claudio Takahasi
@ 2010-11-18 20:01         ` Johan Hedberg
  0 siblings, 0 replies; 13+ messages in thread
From: Johan Hedberg @ 2010-11-18 20:01 UTC (permalink / raw)
  To: Claudio Takahasi; +Cc: linux-bluetooth

Hi Claudio,

On Thu, Nov 18, 2010, Claudio Takahasi wrote:
> Find by type operation is used by Discover Primary Service by Service
> UUID. Find By Type Value Response shall contain one or more group handles.
> ---
>  attrib/att.c |   46 ++++++++++++++++++++++++++++++++++++++++++++++
>  attrib/att.h |    7 +++++++
>  2 files changed, 53 insertions(+), 0 deletions(-)

Thanks for the update. This and the rest of your patches have been
pushed upstream.

Johan

^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2010-11-18 20:01 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-11-17 18:09 [PATCH 1/6] Implement Find by Type request encode/decoding Claudio Takahasi
2010-11-17 18:09 ` [PATCH 2/6] Add Find By Type Value Response encoding/decoding functions Claudio Takahasi
2010-11-18 14:47   ` Johan Hedberg
2010-11-18 15:25     ` Claudio Takahasi
2010-11-18 17:48       ` [PATCH v2 " Claudio Takahasi
2010-11-18 20:01         ` Johan Hedberg
2010-11-17 18:09 ` [PATCH 3/6] Implement Find by Type Value Request in the atttribute server Claudio Takahasi
2010-11-18 18:02   ` [PATCH v2 " Claudio Takahasi
2010-11-17 18:09 ` [PATCH 4/6] Extend bt_string2uuid to convert hex strings to UUID16 Claudio Takahasi
2010-11-17 18:09 ` [PATCH 5/6] Add an extra parameter in the discovery primary to specify the UUID Claudio Takahasi
2010-11-17 18:09 ` [PATCH 6/6] Implement Discover Primary Service by Service UUID in the gatttool Claudio Takahasi
2010-11-18 18:07   ` [PATCH v2 " Claudio Takahasi
2010-11-18 14:45 ` [PATCH 1/6] Implement Find by Type request encode/decoding Johan Hedberg

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.