All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH BlueZ v3 1/7] shared/gatt-client: Fix handling of services
@ 2015-03-19 14:21 Luiz Augusto von Dentz
  2015-03-19 14:21 ` [PATCH BlueZ v3 2/7] unit/test-gatt: Add /TP/GAD/CL/BV-06-C/client-1 test Luiz Augusto von Dentz
                   ` (6 more replies)
  0 siblings, 7 replies; 8+ messages in thread
From: Luiz Augusto von Dentz @ 2015-03-19 14:21 UTC (permalink / raw)
  To: linux-bluetooth

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

Remote services may contain gaps between their handles so they need to be
inserted in a proper position.
---
v2: Fix gatt_db_get_attribute to work with non-sequential handles
v3: Fix gatt_db_service_foreach_desc to work with non-sequential handles

 src/shared/gatt-client.c |   8 ++-
 src/shared/gatt-db.c     | 147 +++++++++++++++++++++++++++++++++++++----------
 src/shared/gatt-db.h     |  17 ++++++
 3 files changed, 139 insertions(+), 33 deletions(-)

diff --git a/src/shared/gatt-client.c b/src/shared/gatt-client.c
index f33d8c9..3e28c6e 100644
--- a/src/shared/gatt-client.c
+++ b/src/shared/gatt-client.c
@@ -588,7 +588,8 @@ static bool discover_descs(struct discovery_op *op, bool *discovering)
 	*discovering = false;
 
 	while ((chrc_data = queue_pop_head(op->pending_chrcs))) {
-		attr = gatt_db_service_add_characteristic(op->cur_svc,
+		attr = gatt_db_service_insert_characteristic(op->cur_svc,
+							chrc_data->value_handle,
 							&chrc_data->uuid, 0,
 							chrc_data->properties,
 							NULL, NULL, NULL);
@@ -679,8 +680,9 @@ static void discover_descs_cb(bool success, uint8_t att_ecode,
 						"handle: 0x%04x, uuid: %s",
 						handle, uuid_str);
 
-		attr = gatt_db_service_add_descriptor(op->cur_svc, &uuid, 0,
-							NULL, NULL, NULL);
+		attr = gatt_db_service_insert_descriptor(op->cur_svc, handle,
+							&uuid, 0, NULL, NULL,
+							NULL);
 		if (!attr)
 			goto failed;
 
diff --git a/src/shared/gatt-db.c b/src/shared/gatt-db.c
index eb81372..2b2090c 100644
--- a/src/shared/gatt-db.c
+++ b/src/shared/gatt-db.c
@@ -158,6 +158,7 @@ static void attribute_destroy(struct gatt_db_attribute *attribute)
 }
 
 static struct gatt_db_attribute *new_attribute(struct gatt_db_service *service,
+							uint16_t handle,
 							const bt_uuid_t *type,
 							const uint8_t *val,
 							uint16_t len)
@@ -169,6 +170,7 @@ static struct gatt_db_attribute *new_attribute(struct gatt_db_service *service,
 		return NULL;
 
 	attribute->service = service;
+	attribute->handle = handle;
 	attribute->uuid = *type;
 	attribute->value_len = len;
 	if (len) {
@@ -371,6 +373,7 @@ static bool le_to_uuid(const uint8_t *src, size_t len, bt_uuid_t *uuid)
 }
 
 static struct gatt_db_service *gatt_db_service_create(const bt_uuid_t *uuid,
+							uint16_t handle,
 							bool primary,
 							uint16_t num_handles)
 {
@@ -399,7 +402,8 @@ static struct gatt_db_service *gatt_db_service_create(const bt_uuid_t *uuid,
 
 	len = uuid_to_le(uuid, value);
 
-	service->attributes[0] = new_attribute(service, type, value, len);
+	service->attributes[0] = new_attribute(service, handle, type, value,
+									len);
 	if (!service->attributes[0]) {
 		gatt_db_service_destroy(service);
 		return NULL;
@@ -533,7 +537,7 @@ struct gatt_db_attribute *gatt_db_insert_service(struct gatt_db *db,
 	if (!find_insert_loc(db, handle, handle + num_handles - 1, &after))
 		return NULL;
 
-	service = gatt_db_service_create(uuid, primary, num_handles);
+	service = gatt_db_service_create(uuid, handle, primary, num_handles);
 
 	if (!service)
 		return NULL;
@@ -663,8 +667,9 @@ static void set_attribute_data(struct gatt_db_attribute *attribute,
 	attribute->user_data = user_data;
 }
 
-struct gatt_db_attribute *
-gatt_db_service_add_characteristic(struct gatt_db_attribute *attrib,
+static struct gatt_db_attribute *
+service_insert_characteristic(struct gatt_db_service *service,
+					uint16_t handle,
 					const bt_uuid_t *uuid,
 					uint32_t permissions,
 					uint8_t properties,
@@ -672,35 +677,38 @@ gatt_db_service_add_characteristic(struct gatt_db_attribute *attrib,
 					gatt_db_write_t write_func,
 					void *user_data)
 {
-	struct gatt_db_service *service;
 	uint8_t value[MAX_CHAR_DECL_VALUE_LEN];
 	uint16_t len = 0;
 	int i;
 
-	if (!attrib)
+	/* Check if handle is in within service range */
+	if (handle && handle <= service->attributes[0]->handle)
 		return NULL;
 
-	service = attrib->service;
-
 	i = get_attribute_index(service, 1);
 	if (!i)
 		return NULL;
 
+	if (!handle)
+		handle = get_handle_at_index(service, i - 1) + 2;
+
 	value[0] = properties;
 	len += sizeof(properties);
+
 	/* We set handle of characteristic value, which will be added next */
-	put_le16(get_handle_at_index(service, i - 1) + 2, &value[1]);
+	put_le16(handle, &value[1]);
 	len += sizeof(uint16_t);
 	len += uuid_to_le(uuid, &value[3]);
 
-	service->attributes[i] = new_attribute(service, &characteristic_uuid,
-								value, len);
+	service->attributes[i] = new_attribute(service, handle - 1,
+							&characteristic_uuid,
+							value, len);
 	if (!service->attributes[i])
 		return NULL;
 
-	attribute_update(service, i++);
+	i++;
 
-	service->attributes[i] = new_attribute(service, uuid, NULL, 0);
+	service->attributes[i] = new_attribute(service, handle, uuid, NULL, 0);
 	if (!service->attributes[i]) {
 		free(service->attributes[i - 1]);
 		return NULL;
@@ -709,37 +717,109 @@ gatt_db_service_add_characteristic(struct gatt_db_attribute *attrib,
 	set_attribute_data(service->attributes[i], read_func, write_func,
 							permissions, user_data);
 
-	return attribute_update(service, i);
+	return service->attributes[i];
 }
 
 struct gatt_db_attribute *
-gatt_db_service_add_descriptor(struct gatt_db_attribute *attrib,
+gatt_db_service_insert_characteristic(struct gatt_db_attribute *attrib,
+					uint16_t handle,
 					const bt_uuid_t *uuid,
 					uint32_t permissions,
+					uint8_t properties,
 					gatt_db_read_t read_func,
 					gatt_db_write_t write_func,
 					void *user_data)
 {
-	struct gatt_db_service *service;
-	int i;
+	if (!attrib || !handle)
+		return NULL;
 
+	return service_insert_characteristic(attrib->service, handle, uuid,
+						permissions, properties,
+						read_func, write_func,
+						user_data);
+}
+
+struct gatt_db_attribute *
+gatt_db_service_add_characteristic(struct gatt_db_attribute *attrib,
+					const bt_uuid_t *uuid,
+					uint32_t permissions,
+					uint8_t properties,
+					gatt_db_read_t read_func,
+					gatt_db_write_t write_func,
+					void *user_data)
+{
 	if (!attrib)
 		return NULL;
 
-	service = attrib->service;
+	return service_insert_characteristic(attrib->service, 0, uuid,
+						permissions, properties,
+						read_func, write_func,
+						user_data);
+}
+
+static struct gatt_db_attribute *
+service_insert_descriptor(struct gatt_db_service *service,
+					uint16_t handle,
+					const bt_uuid_t *uuid,
+					uint32_t permissions,
+					gatt_db_read_t read_func,
+					gatt_db_write_t write_func,
+					void *user_data)
+{
+	int i;
 
 	i = get_attribute_index(service, 0);
 	if (!i)
 		return NULL;
 
-	service->attributes[i] = new_attribute(service, uuid, NULL, 0);
+	/* Check if handle is in within service range */
+	if (handle && handle <= service->attributes[0]->handle)
+		return NULL;
+
+	if (!handle)
+		handle = get_handle_at_index(service, i - 1) + 1;
+
+	service->attributes[i] = new_attribute(service, handle, uuid, NULL, 0);
 	if (!service->attributes[i])
 		return NULL;
 
 	set_attribute_data(service->attributes[i], read_func, write_func,
 							permissions, user_data);
 
-	return attribute_update(service, i);
+	return service->attributes[i];
+}
+
+struct gatt_db_attribute *
+gatt_db_service_insert_descriptor(struct gatt_db_attribute *attrib,
+					uint16_t handle,
+					const bt_uuid_t *uuid,
+					uint32_t permissions,
+					gatt_db_read_t read_func,
+					gatt_db_write_t write_func,
+					void *user_data)
+{
+	if (!attrib || !handle)
+		return NULL;
+
+	return service_insert_descriptor(attrib->service, handle, uuid,
+					permissions, read_func, write_func,
+					user_data);
+}
+
+struct gatt_db_attribute *
+gatt_db_service_add_descriptor(struct gatt_db_attribute *attrib,
+					const bt_uuid_t *uuid,
+					uint32_t permissions,
+					gatt_db_read_t read_func,
+					gatt_db_write_t write_func,
+					void *user_data)
+{
+	if (!attrib)
+		return NULL;
+
+	return service_insert_descriptor(attrib->service, 0, uuid,
+					permissions, read_func, write_func,
+					user_data);
 }
 
 struct gatt_db_attribute *
@@ -781,7 +861,7 @@ gatt_db_service_add_included(struct gatt_db_attribute *attrib,
 	if (!index)
 		return NULL;
 
-	service->attributes[index] = new_attribute(service,
+	service->attributes[index] = new_attribute(service, 0,
 							&included_service_uuid,
 							value, len);
 	if (!service->attributes[index])
@@ -1184,7 +1264,13 @@ void gatt_db_service_foreach_desc(struct gatt_db_attribute *attrib,
 	service = attrib->service;
 
 	/* Start from the attribute following the value handle */
-	i = attrib->handle - service->attributes[0]->handle + 2;
+	for (i = 0; i < service->num_handles; i++) {
+		if (service->attributes[i] == attrib) {
+			i += 2;
+			break;
+		}
+	}
+
 	for (; i < service->num_handles; i++) {
 		attr = service->attributes[i];
 		if (!attr)
@@ -1222,7 +1308,7 @@ struct gatt_db_attribute *gatt_db_get_attribute(struct gatt_db *db,
 							uint16_t handle)
 {
 	struct gatt_db_service *service;
-	uint16_t service_handle;
+	int i;
 
 	if (!db || !handle)
 		return NULL;
@@ -1232,14 +1318,15 @@ struct gatt_db_attribute *gatt_db_get_attribute(struct gatt_db *db,
 	if (!service)
 		return NULL;
 
-	service_handle = service->attributes[0]->handle;
+	for (i = 0; i < service->num_handles; i++) {
+		if (!service->attributes[i])
+			continue;
 
-	/*
-	 * We can safely get attribute from attributes array with offset,
-	 * because find_service_for_handle() check if given handle is
-	 * in service range.
-	 */
-	return service->attributes[handle - service_handle];
+		if (service->attributes[i]->handle == handle)
+			return service->attributes[i];
+	}
+
+	return NULL;
 }
 
 static bool find_service_with_uuid(const void *data, const void *user_data)
diff --git a/src/shared/gatt-db.h b/src/shared/gatt-db.h
index 74b37bc..96cceb9 100644
--- a/src/shared/gatt-db.h
+++ b/src/shared/gatt-db.h
@@ -67,6 +67,15 @@ gatt_db_service_add_characteristic(struct gatt_db_attribute *attrib,
 					gatt_db_read_t read_func,
 					gatt_db_write_t write_func,
 					void *user_data);
+struct gatt_db_attribute *
+gatt_db_service_insert_characteristic(struct gatt_db_attribute *attrib,
+					uint16_t handle,
+					const bt_uuid_t *uuid,
+					uint32_t permissions,
+					uint8_t properties,
+					gatt_db_read_t read_func,
+					gatt_db_write_t write_func,
+					void *user_data);
 
 struct gatt_db_attribute *
 gatt_db_service_add_descriptor(struct gatt_db_attribute *attrib,
@@ -75,6 +84,14 @@ gatt_db_service_add_descriptor(struct gatt_db_attribute *attrib,
 					gatt_db_read_t read_func,
 					gatt_db_write_t write_func,
 					void *user_data);
+struct gatt_db_attribute *
+gatt_db_service_insert_descriptor(struct gatt_db_attribute *attrib,
+					uint16_t handle,
+					const bt_uuid_t *uuid,
+					uint32_t permissions,
+					gatt_db_read_t read_func,
+					gatt_db_write_t write_func,
+					void *user_data);
 
 struct gatt_db_attribute *
 gatt_db_service_add_included(struct gatt_db_attribute *attrib,
-- 
2.1.0


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

* [PATCH BlueZ v3 2/7] unit/test-gatt: Add /TP/GAD/CL/BV-06-C/client-1 test
  2015-03-19 14:21 [PATCH BlueZ v3 1/7] shared/gatt-client: Fix handling of services Luiz Augusto von Dentz
@ 2015-03-19 14:21 ` Luiz Augusto von Dentz
  2015-03-19 14:21 ` [PATCH BlueZ v3 3/7] unit/test-gatt: Add /TP/GAD/CL/BV-06-C/client-2 test Luiz Augusto von Dentz
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Luiz Augusto von Dentz @ 2015-03-19 14:21 UTC (permalink / raw)
  To: linux-bluetooth

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

This is similar to TP/GAD/CL/BV-06-C but using bt_gatt_client to
discover everything.
---
 unit/test-gatt.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/unit/test-gatt.c b/unit/test-gatt.c
index 93ee2c7..33d4b9f 100644
--- a/unit/test-gatt.c
+++ b/unit/test-gatt.c
@@ -2269,6 +2269,10 @@ int main(int argc, char *argv[])
 			raw_pdu(0x05, 0x01, 0x15, 0x00, 0x04, 0x29, 0x16, 0x00,
 					0x05, 0x29));
 
+	define_test_client("/TP/GAD/CL/BV-06-C/client-1", test_client,
+			service_db_1, NULL,
+			SERVICE_DATA_1_PDUS);
+
 	define_test_server("/TP/GAD/SR/BV-06-C/small", test_server,
 			ts_small_db, NULL,
 			raw_pdu(0x03, 0x00, 0x02),
-- 
2.1.0


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

* [PATCH BlueZ v3 3/7] unit/test-gatt: Add /TP/GAD/CL/BV-06-C/client-2 test
  2015-03-19 14:21 [PATCH BlueZ v3 1/7] shared/gatt-client: Fix handling of services Luiz Augusto von Dentz
  2015-03-19 14:21 ` [PATCH BlueZ v3 2/7] unit/test-gatt: Add /TP/GAD/CL/BV-06-C/client-1 test Luiz Augusto von Dentz
@ 2015-03-19 14:21 ` Luiz Augusto von Dentz
  2015-03-19 14:21 ` [PATCH BlueZ v3 4/7] unit/test-gatt: Add /TP/GAD/CL/BV-06-C/client-3 test Luiz Augusto von Dentz
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Luiz Augusto von Dentz @ 2015-03-19 14:21 UTC (permalink / raw)
  To: linux-bluetooth

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

This veryfy we the code is able to parse services with gaps between
handles.
---
 unit/test-gatt.c | 124 ++++++++++++++++++++++++++++++++++++++++++++++++-------
 1 file changed, 109 insertions(+), 15 deletions(-)

diff --git a/unit/test-gatt.c b/unit/test-gatt.c
index 33d4b9f..7bc2d25 100644
--- a/unit/test-gatt.c
+++ b/unit/test-gatt.c
@@ -149,6 +149,35 @@ struct context {
 		raw_pdu(0x04, 0x08, 0x00, 0x08, 0x00),			\
 		raw_pdu(0x05, 0x01, 0x08, 0x00, 0x01, 0x29)
 
+#define SERVICE_DATA_2_PDUS						\
+		MTU_EXCHANGE_CLIENT_PDUS,				\
+		raw_pdu(0x10, 0x01, 0x00, 0xff, 0xff, 0x00, 0x28),	\
+		raw_pdu(0x11, 0x06, 0x01, 0x00, 0x04, 0x00, 0x01, 0x18),\
+		raw_pdu(0x10, 0x05, 0x00, 0xff, 0xff, 0x00, 0x28),	\
+		raw_pdu(0x11, 0x06, 0x05, 0x00, 0x0a, 0x00, 0x0d, 0x18),\
+		raw_pdu(0x10, 0x0b, 0x00, 0xff, 0xff, 0x00, 0x28),	\
+		raw_pdu(0x01, 0x10, 0x0b, 0x00, 0x0a),			\
+		raw_pdu(0x10, 0x01, 0x00, 0xff, 0xff, 0x01, 0x28),	\
+		raw_pdu(0x01, 0x10, 0x01, 0x00, 0x0a),			\
+		raw_pdu(0x08, 0x01, 0x00, 0x04, 0x00, 0x02, 0x28),	\
+		raw_pdu(0x01, 0x08, 0x01, 0x00, 0x0a),			\
+		raw_pdu(0x08, 0x05, 0x00, 0x0a, 0x00, 0x02, 0x28),	\
+		raw_pdu(0x01, 0x08, 0x05, 0x00, 0x0a),			\
+		raw_pdu(0x08, 0x01, 0x00, 0x04, 0x00, 0x03, 0x28),	\
+		raw_pdu(0x09, 0x07, 0x02, 0x00, 0x02, 0x03, 0x00, 0x00,	\
+				0x2a),					\
+		raw_pdu(0x08, 0x03, 0x00, 0x04, 0x00, 0x03, 0x28),	\
+		raw_pdu(0x01, 0x08, 0x03, 0x00, 0x0a),			\
+		raw_pdu(0x04, 0x04, 0x00, 0x04, 0x00),			\
+		raw_pdu(0x05, 0x01, 0x04, 0x00, 0x01, 0x29),		\
+		raw_pdu(0x08, 0x05, 0x00, 0x0a, 0x00, 0x03, 0x28),	\
+		raw_pdu(0x09, 0x07, 0x07, 0x00, 0x0a, 0x08, 0x00, 0x29,	\
+				0x2a),					\
+		raw_pdu(0x08, 0x08, 0x00, 0x0a, 0x00, 0x03, 0x28),	\
+		raw_pdu(0x01, 0x08, 0x08, 0x00, 0x0a),			\
+		raw_pdu(0x04, 0x09, 0x00, 0x0a, 0x00),			\
+		raw_pdu(0x05, 0x01, 0x0a, 0x00, 0x01, 0x29)
+
 #define PRIMARY_DISC_SMALL_DB						\
 		raw_pdu(0x10, 0x01, 0x00, 0xff, 0xff, 0x00, 0x28),	\
 		raw_pdu(0x11, 0x06, 0x10, 0xF0, 0x17, 0xF0, 0x00, 0x18,	\
@@ -966,16 +995,23 @@ static void att_write_cb(struct gatt_db_attribute *att, int err,
 	g_assert(!err);
 }
 
-static struct gatt_db_attribute *add_char_with_value(struct gatt_db *db,
-					struct gatt_db_attribute *service_att,
-					bt_uuid_t *uuid,
-					uint32_t att_permissions,
-					uint8_t char_properties,
-					const void *value, size_t len)
+static struct gatt_db_attribute *
+add_char_with_value(struct gatt_db_attribute *service_att, uint16_t handle,
+				bt_uuid_t *uuid, uint32_t att_permissions,
+				uint8_t char_properties, const void *value,
+				size_t len)
 {
 	struct gatt_db_attribute *attrib;
 
-	attrib = gatt_db_service_add_characteristic(service_att, uuid,
+	if (handle)
+		attrib = gatt_db_service_insert_characteristic(service_att,
+								handle, uuid,
+								att_permissions,
+								char_properties,
+								NULL, NULL,
+								NULL);
+	else
+		attrib = gatt_db_service_add_characteristic(service_att, uuid,
 								att_permissions,
 								char_properties,
 								NULL, NULL,
@@ -990,14 +1026,19 @@ static struct gatt_db_attribute *add_char_with_value(struct gatt_db *db,
 }
 
 static struct gatt_db_attribute *
-add_desc_with_value(struct gatt_db_attribute *att, bt_uuid_t *uuid,
-				uint32_t att_perms, const uint8_t *value,
-				size_t len)
+add_desc_with_value(struct gatt_db_attribute *att, uint16_t handle,
+					bt_uuid_t *uuid, uint32_t att_perms,
+					const uint8_t *value, size_t len)
 {
 	struct gatt_db_attribute *desc_att;
 
-	desc_att = gatt_db_service_add_descriptor(att, uuid, att_perms, NULL,
-								NULL, NULL);
+	if (handle)
+		desc_att = gatt_db_service_insert_descriptor(att, handle, uuid,
+							att_perms, NULL, NULL,
+							NULL);
+	else
+		desc_att = gatt_db_service_add_descriptor(att, uuid, att_perms,
+							NULL, NULL, NULL);
 
 	gatt_db_attribute_write(desc_att, 0, value, len, 0x00, NULL,
 							att_write_cb, NULL);
@@ -1124,7 +1165,7 @@ static struct gatt_db *make_db(const struct att_handle_spec *spec)
 		case CHARACTERISTIC:
 			bt_string_to_uuid(&uuid, spec->uuid);
 
-			add_char_with_value(db, att, &uuid,
+			add_char_with_value(att, spec->handle, &uuid,
 							spec->att_permissions,
 							spec->char_properties,
 							spec->value, spec->len);
@@ -1134,7 +1175,8 @@ static struct gatt_db *make_db(const struct att_handle_spec *spec)
 		case DESCRIPTOR:
 			bt_string_to_uuid(&uuid, spec->uuid);
 
-			add_desc_with_value(att, &uuid, spec->att_permissions,
+			add_desc_with_value(att, spec->handle, &uuid,
+							spec->att_permissions,
 							spec->value, spec->len);
 
 			break;
@@ -1168,6 +1210,52 @@ static struct gatt_db *make_service_data_1_db(void)
 	return make_db(specs);
 }
 
+#define CHARACTERISTIC_STR_AT(chr_handle, chr_uuid, permissions, properties, \
+								string) \
+	{								\
+		.valid = true,						\
+		.handle = chr_handle,					\
+		.type = CHARACTERISTIC,					\
+		.uuid = STR(chr_uuid),					\
+		.att_permissions = permissions,				\
+		.char_properties = properties,				\
+		.value = (uint8_t *)string,				\
+		.len = strlen(string),					\
+	}
+
+#define DESCRIPTOR_STR_AT(desc_handle, desc_uuid, permissions, string)	\
+	{								\
+		.valid = true,						\
+		.handle = desc_handle,					\
+		.type = DESCRIPTOR,					\
+		.uuid = STR(desc_uuid),					\
+		.att_permissions = permissions,				\
+		.value = (uint8_t *)string,				\
+		.len = strlen(string),					\
+	}
+
+static struct gatt_db *make_service_data_2_db(void)
+{
+	const struct att_handle_spec specs[] = {
+		PRIMARY_SERVICE(0x0001, GATT_UUID, 4),
+		CHARACTERISTIC_STR(GATT_CHARAC_DEVICE_NAME, BT_ATT_PERM_READ,
+					BT_GATT_CHRC_PROP_READ, "BlueZ"),
+		DESCRIPTOR_STR(GATT_CHARAC_USER_DESC_UUID, BT_ATT_PERM_READ,
+								"Device Name"),
+		PRIMARY_SERVICE(0x0005, HEART_RATE_UUID, 6),
+		CHARACTERISTIC_STR_AT(0x0008,
+					GATT_CHARAC_MANUFACTURER_NAME_STRING,
+					BT_ATT_PERM_READ,
+					BT_GATT_CHRC_PROP_READ |
+					BT_GATT_CHRC_PROP_WRITE, ""),
+		DESCRIPTOR_STR_AT(0x000a, GATT_CHARAC_USER_DESC_UUID,
+					BT_ATT_PERM_READ, "Manufacturer Name"),
+		{ }
+	};
+
+	return make_db(specs);
+}
+
 /*
  * Defined Test database 1:
  * Tiny database fits into a single minimum sized-pdu.
@@ -1961,11 +2049,13 @@ static const struct test_step test_indication_server_1 = {
 
 int main(int argc, char *argv[])
 {
-	struct gatt_db *service_db_1, *ts_small_db, *ts_large_db_1;
+	struct gatt_db *service_db_1, *service_db_2;
+	struct gatt_db *ts_small_db, *ts_large_db_1;
 
 	tester_init(&argc, &argv);
 
 	service_db_1 = make_service_data_1_db();
+	service_db_2 = make_service_data_2_db();
 	ts_small_db = make_test_spec_small_db();
 	ts_large_db_1 = make_test_spec_large_db_1();
 
@@ -2273,6 +2363,10 @@ int main(int argc, char *argv[])
 			service_db_1, NULL,
 			SERVICE_DATA_1_PDUS);
 
+	define_test_client("/TP/GAD/CL/BV-06-C/client-2", test_client,
+			service_db_2, NULL,
+			SERVICE_DATA_2_PDUS);
+
 	define_test_server("/TP/GAD/SR/BV-06-C/small", test_server,
 			ts_small_db, NULL,
 			raw_pdu(0x03, 0x00, 0x02),
-- 
2.1.0


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

* [PATCH BlueZ v3 4/7] unit/test-gatt: Add /TP/GAD/CL/BV-06-C/client-3 test
  2015-03-19 14:21 [PATCH BlueZ v3 1/7] shared/gatt-client: Fix handling of services Luiz Augusto von Dentz
  2015-03-19 14:21 ` [PATCH BlueZ v3 2/7] unit/test-gatt: Add /TP/GAD/CL/BV-06-C/client-1 test Luiz Augusto von Dentz
  2015-03-19 14:21 ` [PATCH BlueZ v3 3/7] unit/test-gatt: Add /TP/GAD/CL/BV-06-C/client-2 test Luiz Augusto von Dentz
@ 2015-03-19 14:21 ` Luiz Augusto von Dentz
  2015-03-19 14:21 ` [PATCH BlueZ v3 5/7] shared/gatt-client: Fix service discovery Luiz Augusto von Dentz
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Luiz Augusto von Dentz @ 2015-03-19 14:21 UTC (permalink / raw)
  To: linux-bluetooth

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

This verify the code is able to parse services with different gaps
between handles.
---
 unit/test-gatt.c | 87 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 86 insertions(+), 1 deletion(-)

diff --git a/unit/test-gatt.c b/unit/test-gatt.c
index 7bc2d25..f1f814a 100644
--- a/unit/test-gatt.c
+++ b/unit/test-gatt.c
@@ -178,6 +178,36 @@ struct context {
 		raw_pdu(0x04, 0x09, 0x00, 0x0a, 0x00),			\
 		raw_pdu(0x05, 0x01, 0x0a, 0x00, 0x01, 0x29)
 
+#define SERVICE_DATA_3_PDUS						\
+		MTU_EXCHANGE_CLIENT_PDUS,				\
+		raw_pdu(0x10, 0x01, 0x00, 0xff, 0xff, 0x00, 0x28),	\
+		raw_pdu(0x11, 0x06, 0x00, 0x01, 0x21, 0x01, 0x00, 0x18, \
+			0x00, 0x02, 0x00, 0x02, 0x01, 0x18),		\
+		raw_pdu(0x10, 0x01, 0x02, 0xff, 0xff, 0x00, 0x28),	\
+		raw_pdu(0x11, 0x06, 0x00, 0x03, 0x20, 0x03, 0x0d, 0x18),\
+		raw_pdu(0x10, 0x21, 0x03, 0xff, 0xff, 0x00, 0x28),	\
+		raw_pdu(0x01, 0x10, 0x21, 0x03, 0x0a),			\
+		raw_pdu(0x10, 0x01, 0x00, 0xff, 0xff, 0x01, 0x28),	\
+		raw_pdu(0x01, 0x10, 0x01, 0x00, 0x0a),			\
+		raw_pdu(0x08, 0x00, 0x01, 0x21, 0x01, 0x02, 0x28),	\
+		raw_pdu(0x01, 0x08, 0x00, 0x01, 0x0a),			\
+		raw_pdu(0x08, 0x00, 0x03, 0x20, 0x03, 0x02, 0x28),	\
+		raw_pdu(0x01, 0x08, 0x00, 0x03, 0x0a),			\
+		raw_pdu(0x08, 0x00, 0x01, 0x21, 0x01, 0x03, 0x28),	\
+		raw_pdu(0x09, 0x07, 0x10, 0x01, 0x02, 0x11, 0x01, 0x00,	\
+			0x2a, 0x20, 0x01, 0x02, 0x21, 0x01, 0x01, 0x2a),\
+		raw_pdu(0x08, 0x21, 0x01, 0x21, 0x01, 0x03, 0x28),	\
+		raw_pdu(0x01, 0x08, 0x21, 0x01, 0x0a),			\
+		raw_pdu(0x04, 0x12, 0x01, 0x1f, 0x01),			\
+		raw_pdu(0x01, 0x04, 0x12, 0x01, 0x0a),			\
+		raw_pdu(0x08, 0x00, 0x03, 0x20, 0x03, 0x03, 0x28),	\
+		raw_pdu(0x09, 0x07, 0x10, 0x03, 0x0a, 0x11, 0x03, 0x29,	\
+			0x2a),						\
+		raw_pdu(0x08, 0x11, 0x03, 0x20, 0x03, 0x03, 0x28),	\
+		raw_pdu(0x01, 0x08, 0x11, 0x03, 0x0a),			\
+		raw_pdu(0x04, 0x12, 0x03, 0x20, 0x03),			\
+		raw_pdu(0x05, 0x01, 0x20, 0x03, 0x02, 0x29)
+
 #define PRIMARY_DISC_SMALL_DB						\
 		raw_pdu(0x10, 0x01, 0x00, 0xff, 0xff, 0x00, 0x28),	\
 		raw_pdu(0x11, 0x06, 0x10, 0xF0, 0x17, 0xF0, 0x00, 0x18,	\
@@ -1256,6 +1286,56 @@ static struct gatt_db *make_service_data_2_db(void)
 	return make_db(specs);
 }
 
+#define CHARACTERISTIC_AT(chr_handle, chr_uuid, permissions, properties, \
+							bytes...)	\
+	{								\
+		.valid = true,						\
+		.handle = chr_handle,					\
+		.type = CHARACTERISTIC,					\
+		.uuid = STR(chr_uuid),					\
+		.att_permissions = permissions,				\
+		.char_properties = properties,				\
+		.value = data(bytes),					\
+		.len = sizeof(data(bytes)),				\
+	}
+
+#define DESCRIPTOR_AT(desc_handle, desc_uuid, permissions, bytes...)	\
+	{								\
+		.valid = true,						\
+		.handle = desc_handle,					\
+		.type = DESCRIPTOR,					\
+		.uuid = STR(desc_uuid),					\
+		.att_permissions = permissions,				\
+		.value = data(bytes),					\
+		.len = sizeof(data(bytes)),				\
+	}
+
+static struct gatt_db *make_service_data_3_db(void)
+{
+	const struct att_handle_spec specs[] = {
+		PRIMARY_SERVICE(0x0100, GAP_UUID, 0x0121 - 0x0100 + 1),
+		CHARACTERISTIC_STR_AT(0x0111, GATT_CHARAC_DEVICE_NAME,
+					BT_ATT_PERM_READ,
+					BT_GATT_CHRC_PROP_READ, "BlueZ"),
+		CHARACTERISTIC_AT(0x0121, GATT_CHARAC_APPEARANCE,
+					BT_ATT_PERM_READ,
+					BT_GATT_CHRC_PROP_READ, 0x00, 0x00),
+		PRIMARY_SERVICE(0x0200, GATT_UUID, 0x0200 - 0x0200 + 1),
+		PRIMARY_SERVICE(0x0300, HEART_RATE_UUID, 0x0320 - 0x0300 + 1),
+		CHARACTERISTIC_STR_AT(0x0311,
+					GATT_CHARAC_MANUFACTURER_NAME_STRING,
+					BT_ATT_PERM_READ,
+					BT_GATT_CHRC_PROP_READ |
+					BT_GATT_CHRC_PROP_WRITE, ""),
+		DESCRIPTOR_AT(0x0320, GATT_CLIENT_CHARAC_CFG_UUID,
+					BT_ATT_PERM_READ | BT_ATT_PERM_WRITE,
+					0x00, 0x00),
+		{ }
+	};
+
+	return make_db(specs);
+}
+
 /*
  * Defined Test database 1:
  * Tiny database fits into a single minimum sized-pdu.
@@ -2049,13 +2129,14 @@ static const struct test_step test_indication_server_1 = {
 
 int main(int argc, char *argv[])
 {
-	struct gatt_db *service_db_1, *service_db_2;
+	struct gatt_db *service_db_1, *service_db_2, *service_db_3;
 	struct gatt_db *ts_small_db, *ts_large_db_1;
 
 	tester_init(&argc, &argv);
 
 	service_db_1 = make_service_data_1_db();
 	service_db_2 = make_service_data_2_db();
+	service_db_3 = make_service_data_3_db();
 	ts_small_db = make_test_spec_small_db();
 	ts_large_db_1 = make_test_spec_large_db_1();
 
@@ -2367,6 +2448,10 @@ int main(int argc, char *argv[])
 			service_db_2, NULL,
 			SERVICE_DATA_2_PDUS);
 
+	define_test_client("/TP/GAD/CL/BV-06-C/client-3", test_client,
+			service_db_3, NULL,
+			SERVICE_DATA_3_PDUS);
+
 	define_test_server("/TP/GAD/SR/BV-06-C/small", test_server,
 			ts_small_db, NULL,
 			raw_pdu(0x03, 0x00, 0x02),
-- 
2.1.0


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

* [PATCH BlueZ v3 5/7] shared/gatt-client: Fix service discovery
  2015-03-19 14:21 [PATCH BlueZ v3 1/7] shared/gatt-client: Fix handling of services Luiz Augusto von Dentz
                   ` (2 preceding siblings ...)
  2015-03-19 14:21 ` [PATCH BlueZ v3 4/7] unit/test-gatt: Add /TP/GAD/CL/BV-06-C/client-3 test Luiz Augusto von Dentz
@ 2015-03-19 14:21 ` Luiz Augusto von Dentz
  2015-03-19 14:21 ` [PATCH BlueZ v3 6/7] core/gatt: Fix not replying if db operation fail Luiz Augusto von Dentz
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Luiz Augusto von Dentz @ 2015-03-19 14:21 UTC (permalink / raw)
  To: linux-bluetooth

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

The code should proceed to discover all descriptors before moving to
next service otherwise it may attempt to insert characteristics in the
wrong service which would probably fail.
---
 src/shared/gatt-client.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/shared/gatt-client.c b/src/shared/gatt-client.c
index 3e28c6e..729bd87 100644
--- a/src/shared/gatt-client.c
+++ b/src/shared/gatt-client.c
@@ -690,13 +690,13 @@ static void discover_descs_cb(bool success, uint8_t att_ecode,
 			goto failed;
 	}
 
+next:
 	if (!discover_descs(op, &discovering))
 		goto failed;
 
 	if (discovering)
 		return;
 
-next:
 	/* Done with the current service */
 	gatt_db_service_set_active(op->cur_svc, true);
 
-- 
2.1.0


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

* [PATCH BlueZ v3 6/7] core/gatt: Fix not replying if db operation fail
  2015-03-19 14:21 [PATCH BlueZ v3 1/7] shared/gatt-client: Fix handling of services Luiz Augusto von Dentz
                   ` (3 preceding siblings ...)
  2015-03-19 14:21 ` [PATCH BlueZ v3 5/7] shared/gatt-client: Fix service discovery Luiz Augusto von Dentz
@ 2015-03-19 14:21 ` Luiz Augusto von Dentz
  2015-03-19 14:21 ` [PATCH BlueZ v3 7/7] core/gatt: Check if attribute is valid Luiz Augusto von Dentz
  2015-03-20  9:19 ` [PATCH BlueZ v3 1/7] shared/gatt-client: Fix handling of services Luiz Augusto von Dentz
  6 siblings, 0 replies; 8+ messages in thread
From: Luiz Augusto von Dentz @ 2015-03-19 14:21 UTC (permalink / raw)
  To: linux-bluetooth

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

---
 src/gatt-client.c | 61 ++++++++++++++++++++++++++++++++++++-------------------
 1 file changed, 40 insertions(+), 21 deletions(-)

diff --git a/src/gatt-client.c b/src/gatt-client.c
index a85b9d2..8f67db3 100644
--- a/src/gatt-client.c
+++ b/src/gatt-client.c
@@ -344,20 +344,19 @@ static void desc_read_cb(bool success, uint8_t att_ecode,
 	struct async_dbus_op *op = user_data;
 	struct descriptor *desc = op->data;
 	struct service *service = desc->chrc->service;
+	DBusMessage *reply;
 
-	if (!success) {
-		DBusMessage *reply = create_gatt_dbus_error(op->msg, att_ecode);
-
-		desc->read_id = 0;
-		g_dbus_send_message(btd_get_dbus_connection(), reply);
-		return;
-	}
+	if (!success)
+		goto fail;
 
 	if (!op->offset)
 		gatt_db_attribute_reset(desc->attr);
 
-	gatt_db_attribute_write(desc->attr, op->offset, value, length, 0, NULL,
-						write_descriptor_cb, desc);
+	if (gatt_db_attribute_write(desc->attr, op->offset, value, length, 0,
+					NULL, write_descriptor_cb, desc)) {
+		error("Failed to store attribute");
+		goto fail;
+	}
 
 	/*
 	 * If the value length is exactly MTU-1, then we may not have read the
@@ -377,10 +376,21 @@ static void desc_read_cb(bool success, uint8_t att_ecode,
 			return;
 	}
 
+	/* Read the stored data from db */
+	if (gatt_db_attribute_read(desc->attr, 0, 0, NULL, read_op_cb, op)) {
+		error("Failed to read database");
+		goto fail;
+	}
+
 	desc->read_id = 0;
 
-	/* Read the stored data from db */
-	gatt_db_attribute_read(desc->attr, 0, 0, NULL, read_op_cb, op);
+	return;
+
+fail:
+	reply = create_gatt_dbus_error(op->msg, att_ecode);
+	desc->read_id = 0;
+	g_dbus_send_message(btd_get_dbus_connection(), reply);
+	return;
 }
 
 static DBusMessage *descriptor_read_value(DBusConnection *conn,
@@ -778,20 +788,19 @@ static void chrc_read_cb(bool success, uint8_t att_ecode, const uint8_t *value,
 	struct async_dbus_op *op = user_data;
 	struct characteristic *chrc = op->data;
 	struct service *service = chrc->service;
+	DBusMessage *reply;
 
-	if (!success) {
-		DBusMessage *reply = create_gatt_dbus_error(op->msg, att_ecode);
-
-		chrc->read_id = 0;
-		g_dbus_send_message(btd_get_dbus_connection(), reply);
-		return ;
-	}
+	if (!success)
+		goto fail;
 
 	if (!op->offset)
 		gatt_db_attribute_reset(chrc->attr);
 
-	gatt_db_attribute_write(chrc->attr, op->offset, value, length, 0, NULL,
-						write_characteristic_cb, chrc);
+	if (!gatt_db_attribute_write(chrc->attr, op->offset, value, length, 0,
+					NULL, write_characteristic_cb, chrc)) {
+		error("Failed to store attribute");
+		goto fail;
+	}
 
 	/*
 	 * If the value length is exactly MTU-1, then we may not have read the
@@ -814,7 +823,17 @@ static void chrc_read_cb(bool success, uint8_t att_ecode, const uint8_t *value,
 	chrc->read_id = 0;
 
 	/* Read the stored data from db */
-	gatt_db_attribute_read(chrc->attr, 0, 0, NULL, read_op_cb, op);
+	if (!gatt_db_attribute_read(chrc->attr, 0, 0, NULL, read_op_cb, op)) {
+		error("Failed to read database");
+		goto fail;
+	}
+
+	return;
+
+fail:
+	reply = create_gatt_dbus_error(op->msg, att_ecode);
+	chrc->read_id = 0;
+	g_dbus_send_message(btd_get_dbus_connection(), reply);
 }
 
 static DBusMessage *characteristic_read_value(DBusConnection *conn,
-- 
2.1.0


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

* [PATCH BlueZ v3 7/7] core/gatt: Check if attribute is valid
  2015-03-19 14:21 [PATCH BlueZ v3 1/7] shared/gatt-client: Fix handling of services Luiz Augusto von Dentz
                   ` (4 preceding siblings ...)
  2015-03-19 14:21 ` [PATCH BlueZ v3 6/7] core/gatt: Fix not replying if db operation fail Luiz Augusto von Dentz
@ 2015-03-19 14:21 ` Luiz Augusto von Dentz
  2015-03-20  9:19 ` [PATCH BlueZ v3 1/7] shared/gatt-client: Fix handling of services Luiz Augusto von Dentz
  6 siblings, 0 replies; 8+ messages in thread
From: Luiz Augusto von Dentz @ 2015-03-19 14:21 UTC (permalink / raw)
  To: linux-bluetooth

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

This checks the return of gatt_db_get_attribute and fail if return NULL.
---
 src/gatt-client.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/src/gatt-client.c b/src/gatt-client.c
index 8f67db3..608f96d 100644
--- a/src/gatt-client.c
+++ b/src/gatt-client.c
@@ -1339,8 +1339,15 @@ static struct characteristic *characteristic_create(
 	gatt_db_attribute_get_char_data(attr, &chrc->handle,
 							&chrc->value_handle,
 							&chrc->props, &uuid);
+
 	chrc->attr = gatt_db_get_attribute(service->client->db,
 							chrc->value_handle);
+	if (!chrc->attr) {
+		error("Attribute 0x%04x not found", chrc->value_handle);
+		characteristic_free(chrc);
+		return NULL;
+	}
+
 	bt_uuid_to_uuid128(&uuid, &chrc->uuid);
 
 	chrc->path = g_strdup_printf("%s/char%04x", service->path,
-- 
2.1.0


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

* Re: [PATCH BlueZ v3 1/7] shared/gatt-client: Fix handling of services
  2015-03-19 14:21 [PATCH BlueZ v3 1/7] shared/gatt-client: Fix handling of services Luiz Augusto von Dentz
                   ` (5 preceding siblings ...)
  2015-03-19 14:21 ` [PATCH BlueZ v3 7/7] core/gatt: Check if attribute is valid Luiz Augusto von Dentz
@ 2015-03-20  9:19 ` Luiz Augusto von Dentz
  6 siblings, 0 replies; 8+ messages in thread
From: Luiz Augusto von Dentz @ 2015-03-20  9:19 UTC (permalink / raw)
  To: linux-bluetooth

Hi,

On Thu, Mar 19, 2015 at 4:21 PM, Luiz Augusto von Dentz
<luiz.dentz@gmail.com> wrote:
> From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
>
> Remote services may contain gaps between their handles so they need to be
> inserted in a proper position.
> ---
> v2: Fix gatt_db_get_attribute to work with non-sequential handles
> v3: Fix gatt_db_service_foreach_desc to work with non-sequential handles
>
>  src/shared/gatt-client.c |   8 ++-
>  src/shared/gatt-db.c     | 147 +++++++++++++++++++++++++++++++++++++----------
>  src/shared/gatt-db.h     |  17 ++++++
>  3 files changed, 139 insertions(+), 33 deletions(-)
>
> diff --git a/src/shared/gatt-client.c b/src/shared/gatt-client.c
> index f33d8c9..3e28c6e 100644
> --- a/src/shared/gatt-client.c
> +++ b/src/shared/gatt-client.c
> @@ -588,7 +588,8 @@ static bool discover_descs(struct discovery_op *op, bool *discovering)
>         *discovering = false;
>
>         while ((chrc_data = queue_pop_head(op->pending_chrcs))) {
> -               attr = gatt_db_service_add_characteristic(op->cur_svc,
> +               attr = gatt_db_service_insert_characteristic(op->cur_svc,
> +                                                       chrc_data->value_handle,
>                                                         &chrc_data->uuid, 0,
>                                                         chrc_data->properties,
>                                                         NULL, NULL, NULL);
> @@ -679,8 +680,9 @@ static void discover_descs_cb(bool success, uint8_t att_ecode,
>                                                 "handle: 0x%04x, uuid: %s",
>                                                 handle, uuid_str);
>
> -               attr = gatt_db_service_add_descriptor(op->cur_svc, &uuid, 0,
> -                                                       NULL, NULL, NULL);
> +               attr = gatt_db_service_insert_descriptor(op->cur_svc, handle,
> +                                                       &uuid, 0, NULL, NULL,
> +                                                       NULL);
>                 if (!attr)
>                         goto failed;
>
> diff --git a/src/shared/gatt-db.c b/src/shared/gatt-db.c
> index eb81372..2b2090c 100644
> --- a/src/shared/gatt-db.c
> +++ b/src/shared/gatt-db.c
> @@ -158,6 +158,7 @@ static void attribute_destroy(struct gatt_db_attribute *attribute)
>  }
>
>  static struct gatt_db_attribute *new_attribute(struct gatt_db_service *service,
> +                                                       uint16_t handle,
>                                                         const bt_uuid_t *type,
>                                                         const uint8_t *val,
>                                                         uint16_t len)
> @@ -169,6 +170,7 @@ static struct gatt_db_attribute *new_attribute(struct gatt_db_service *service,
>                 return NULL;
>
>         attribute->service = service;
> +       attribute->handle = handle;
>         attribute->uuid = *type;
>         attribute->value_len = len;
>         if (len) {
> @@ -371,6 +373,7 @@ static bool le_to_uuid(const uint8_t *src, size_t len, bt_uuid_t *uuid)
>  }
>
>  static struct gatt_db_service *gatt_db_service_create(const bt_uuid_t *uuid,
> +                                                       uint16_t handle,
>                                                         bool primary,
>                                                         uint16_t num_handles)
>  {
> @@ -399,7 +402,8 @@ static struct gatt_db_service *gatt_db_service_create(const bt_uuid_t *uuid,
>
>         len = uuid_to_le(uuid, value);
>
> -       service->attributes[0] = new_attribute(service, type, value, len);
> +       service->attributes[0] = new_attribute(service, handle, type, value,
> +                                                                       len);
>         if (!service->attributes[0]) {
>                 gatt_db_service_destroy(service);
>                 return NULL;
> @@ -533,7 +537,7 @@ struct gatt_db_attribute *gatt_db_insert_service(struct gatt_db *db,
>         if (!find_insert_loc(db, handle, handle + num_handles - 1, &after))
>                 return NULL;
>
> -       service = gatt_db_service_create(uuid, primary, num_handles);
> +       service = gatt_db_service_create(uuid, handle, primary, num_handles);
>
>         if (!service)
>                 return NULL;
> @@ -663,8 +667,9 @@ static void set_attribute_data(struct gatt_db_attribute *attribute,
>         attribute->user_data = user_data;
>  }
>
> -struct gatt_db_attribute *
> -gatt_db_service_add_characteristic(struct gatt_db_attribute *attrib,
> +static struct gatt_db_attribute *
> +service_insert_characteristic(struct gatt_db_service *service,
> +                                       uint16_t handle,
>                                         const bt_uuid_t *uuid,
>                                         uint32_t permissions,
>                                         uint8_t properties,
> @@ -672,35 +677,38 @@ gatt_db_service_add_characteristic(struct gatt_db_attribute *attrib,
>                                         gatt_db_write_t write_func,
>                                         void *user_data)
>  {
> -       struct gatt_db_service *service;
>         uint8_t value[MAX_CHAR_DECL_VALUE_LEN];
>         uint16_t len = 0;
>         int i;
>
> -       if (!attrib)
> +       /* Check if handle is in within service range */
> +       if (handle && handle <= service->attributes[0]->handle)
>                 return NULL;
>
> -       service = attrib->service;
> -
>         i = get_attribute_index(service, 1);
>         if (!i)
>                 return NULL;
>
> +       if (!handle)
> +               handle = get_handle_at_index(service, i - 1) + 2;
> +
>         value[0] = properties;
>         len += sizeof(properties);
> +
>         /* We set handle of characteristic value, which will be added next */
> -       put_le16(get_handle_at_index(service, i - 1) + 2, &value[1]);
> +       put_le16(handle, &value[1]);
>         len += sizeof(uint16_t);
>         len += uuid_to_le(uuid, &value[3]);
>
> -       service->attributes[i] = new_attribute(service, &characteristic_uuid,
> -                                                               value, len);
> +       service->attributes[i] = new_attribute(service, handle - 1,
> +                                                       &characteristic_uuid,
> +                                                       value, len);
>         if (!service->attributes[i])
>                 return NULL;
>
> -       attribute_update(service, i++);
> +       i++;
>
> -       service->attributes[i] = new_attribute(service, uuid, NULL, 0);
> +       service->attributes[i] = new_attribute(service, handle, uuid, NULL, 0);
>         if (!service->attributes[i]) {
>                 free(service->attributes[i - 1]);
>                 return NULL;
> @@ -709,37 +717,109 @@ gatt_db_service_add_characteristic(struct gatt_db_attribute *attrib,
>         set_attribute_data(service->attributes[i], read_func, write_func,
>                                                         permissions, user_data);
>
> -       return attribute_update(service, i);
> +       return service->attributes[i];
>  }
>
>  struct gatt_db_attribute *
> -gatt_db_service_add_descriptor(struct gatt_db_attribute *attrib,
> +gatt_db_service_insert_characteristic(struct gatt_db_attribute *attrib,
> +                                       uint16_t handle,
>                                         const bt_uuid_t *uuid,
>                                         uint32_t permissions,
> +                                       uint8_t properties,
>                                         gatt_db_read_t read_func,
>                                         gatt_db_write_t write_func,
>                                         void *user_data)
>  {
> -       struct gatt_db_service *service;
> -       int i;
> +       if (!attrib || !handle)
> +               return NULL;
>
> +       return service_insert_characteristic(attrib->service, handle, uuid,
> +                                               permissions, properties,
> +                                               read_func, write_func,
> +                                               user_data);
> +}
> +
> +struct gatt_db_attribute *
> +gatt_db_service_add_characteristic(struct gatt_db_attribute *attrib,
> +                                       const bt_uuid_t *uuid,
> +                                       uint32_t permissions,
> +                                       uint8_t properties,
> +                                       gatt_db_read_t read_func,
> +                                       gatt_db_write_t write_func,
> +                                       void *user_data)
> +{
>         if (!attrib)
>                 return NULL;
>
> -       service = attrib->service;
> +       return service_insert_characteristic(attrib->service, 0, uuid,
> +                                               permissions, properties,
> +                                               read_func, write_func,
> +                                               user_data);
> +}
> +
> +static struct gatt_db_attribute *
> +service_insert_descriptor(struct gatt_db_service *service,
> +                                       uint16_t handle,
> +                                       const bt_uuid_t *uuid,
> +                                       uint32_t permissions,
> +                                       gatt_db_read_t read_func,
> +                                       gatt_db_write_t write_func,
> +                                       void *user_data)
> +{
> +       int i;
>
>         i = get_attribute_index(service, 0);
>         if (!i)
>                 return NULL;
>
> -       service->attributes[i] = new_attribute(service, uuid, NULL, 0);
> +       /* Check if handle is in within service range */
> +       if (handle && handle <= service->attributes[0]->handle)
> +               return NULL;
> +
> +       if (!handle)
> +               handle = get_handle_at_index(service, i - 1) + 1;
> +
> +       service->attributes[i] = new_attribute(service, handle, uuid, NULL, 0);
>         if (!service->attributes[i])
>                 return NULL;
>
>         set_attribute_data(service->attributes[i], read_func, write_func,
>                                                         permissions, user_data);
>
> -       return attribute_update(service, i);
> +       return service->attributes[i];
> +}
> +
> +struct gatt_db_attribute *
> +gatt_db_service_insert_descriptor(struct gatt_db_attribute *attrib,
> +                                       uint16_t handle,
> +                                       const bt_uuid_t *uuid,
> +                                       uint32_t permissions,
> +                                       gatt_db_read_t read_func,
> +                                       gatt_db_write_t write_func,
> +                                       void *user_data)
> +{
> +       if (!attrib || !handle)
> +               return NULL;
> +
> +       return service_insert_descriptor(attrib->service, handle, uuid,
> +                                       permissions, read_func, write_func,
> +                                       user_data);
> +}
> +
> +struct gatt_db_attribute *
> +gatt_db_service_add_descriptor(struct gatt_db_attribute *attrib,
> +                                       const bt_uuid_t *uuid,
> +                                       uint32_t permissions,
> +                                       gatt_db_read_t read_func,
> +                                       gatt_db_write_t write_func,
> +                                       void *user_data)
> +{
> +       if (!attrib)
> +               return NULL;
> +
> +       return service_insert_descriptor(attrib->service, 0, uuid,
> +                                       permissions, read_func, write_func,
> +                                       user_data);
>  }
>
>  struct gatt_db_attribute *
> @@ -781,7 +861,7 @@ gatt_db_service_add_included(struct gatt_db_attribute *attrib,
>         if (!index)
>                 return NULL;
>
> -       service->attributes[index] = new_attribute(service,
> +       service->attributes[index] = new_attribute(service, 0,
>                                                         &included_service_uuid,
>                                                         value, len);
>         if (!service->attributes[index])
> @@ -1184,7 +1264,13 @@ void gatt_db_service_foreach_desc(struct gatt_db_attribute *attrib,
>         service = attrib->service;
>
>         /* Start from the attribute following the value handle */
> -       i = attrib->handle - service->attributes[0]->handle + 2;
> +       for (i = 0; i < service->num_handles; i++) {
> +               if (service->attributes[i] == attrib) {
> +                       i += 2;
> +                       break;
> +               }
> +       }
> +
>         for (; i < service->num_handles; i++) {
>                 attr = service->attributes[i];
>                 if (!attr)
> @@ -1222,7 +1308,7 @@ struct gatt_db_attribute *gatt_db_get_attribute(struct gatt_db *db,
>                                                         uint16_t handle)
>  {
>         struct gatt_db_service *service;
> -       uint16_t service_handle;
> +       int i;
>
>         if (!db || !handle)
>                 return NULL;
> @@ -1232,14 +1318,15 @@ struct gatt_db_attribute *gatt_db_get_attribute(struct gatt_db *db,
>         if (!service)
>                 return NULL;
>
> -       service_handle = service->attributes[0]->handle;
> +       for (i = 0; i < service->num_handles; i++) {
> +               if (!service->attributes[i])
> +                       continue;
>
> -       /*
> -        * We can safely get attribute from attributes array with offset,
> -        * because find_service_for_handle() check if given handle is
> -        * in service range.
> -        */
> -       return service->attributes[handle - service_handle];
> +               if (service->attributes[i]->handle == handle)
> +                       return service->attributes[i];
> +       }
> +
> +       return NULL;
>  }
>
>  static bool find_service_with_uuid(const void *data, const void *user_data)
> diff --git a/src/shared/gatt-db.h b/src/shared/gatt-db.h
> index 74b37bc..96cceb9 100644
> --- a/src/shared/gatt-db.h
> +++ b/src/shared/gatt-db.h
> @@ -67,6 +67,15 @@ gatt_db_service_add_characteristic(struct gatt_db_attribute *attrib,
>                                         gatt_db_read_t read_func,
>                                         gatt_db_write_t write_func,
>                                         void *user_data);
> +struct gatt_db_attribute *
> +gatt_db_service_insert_characteristic(struct gatt_db_attribute *attrib,
> +                                       uint16_t handle,
> +                                       const bt_uuid_t *uuid,
> +                                       uint32_t permissions,
> +                                       uint8_t properties,
> +                                       gatt_db_read_t read_func,
> +                                       gatt_db_write_t write_func,
> +                                       void *user_data);
>
>  struct gatt_db_attribute *
>  gatt_db_service_add_descriptor(struct gatt_db_attribute *attrib,
> @@ -75,6 +84,14 @@ gatt_db_service_add_descriptor(struct gatt_db_attribute *attrib,
>                                         gatt_db_read_t read_func,
>                                         gatt_db_write_t write_func,
>                                         void *user_data);
> +struct gatt_db_attribute *
> +gatt_db_service_insert_descriptor(struct gatt_db_attribute *attrib,
> +                                       uint16_t handle,
> +                                       const bt_uuid_t *uuid,
> +                                       uint32_t permissions,
> +                                       gatt_db_read_t read_func,
> +                                       gatt_db_write_t write_func,
> +                                       void *user_data);
>
>  struct gatt_db_attribute *
>  gatt_db_service_add_included(struct gatt_db_attribute *attrib,
> --
> 2.1.0

Applied.


-- 
Luiz Augusto von Dentz

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

end of thread, other threads:[~2015-03-20  9:19 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-03-19 14:21 [PATCH BlueZ v3 1/7] shared/gatt-client: Fix handling of services Luiz Augusto von Dentz
2015-03-19 14:21 ` [PATCH BlueZ v3 2/7] unit/test-gatt: Add /TP/GAD/CL/BV-06-C/client-1 test Luiz Augusto von Dentz
2015-03-19 14:21 ` [PATCH BlueZ v3 3/7] unit/test-gatt: Add /TP/GAD/CL/BV-06-C/client-2 test Luiz Augusto von Dentz
2015-03-19 14:21 ` [PATCH BlueZ v3 4/7] unit/test-gatt: Add /TP/GAD/CL/BV-06-C/client-3 test Luiz Augusto von Dentz
2015-03-19 14:21 ` [PATCH BlueZ v3 5/7] shared/gatt-client: Fix service discovery Luiz Augusto von Dentz
2015-03-19 14:21 ` [PATCH BlueZ v3 6/7] core/gatt: Fix not replying if db operation fail Luiz Augusto von Dentz
2015-03-19 14:21 ` [PATCH BlueZ v3 7/7] core/gatt: Check if attribute is valid Luiz Augusto von Dentz
2015-03-20  9:19 ` [PATCH BlueZ v3 1/7] shared/gatt-client: Fix handling of services Luiz Augusto von Dentz

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.