Diff between 45f0f541422a8f8708e946e3e1ea56fc5482928f and 6b3f0f3ab935e192db9cf73b68a27271d4febd74

Changed Files

File Additions Deletions Status
src/shared/gatt-client.c +114 -0 modified
unit/test-gatt.c +2 -0 modified

Full Patch

diff --git a/src/shared/gatt-client.c b/src/shared/gatt-client.c
index ff49be1..84689f6 100644
--- a/src/shared/gatt-client.c
+++ b/src/shared/gatt-client.c
@@ -316,6 +316,7 @@ struct discovery_op {
 	struct queue *pending_svcs;
 	struct queue *pending_chrcs;
 	struct queue *svcs;
+	struct queue *ext_prop_desc;
 	struct gatt_db_attribute *cur_svc;
 	bool success;
 	uint16_t start;
@@ -331,6 +332,7 @@ static void discovery_op_free(struct discovery_op *op)
 	queue_destroy(op->pending_svcs, NULL);
 	queue_destroy(op->pending_chrcs, free);
 	queue_destroy(op->svcs, NULL);
+	queue_destroy(op->ext_prop_desc, NULL);
 	free(op);
 }
 
@@ -360,6 +362,7 @@ static struct discovery_op *discovery_op_create(struct bt_gatt_client *client,
 	op->pending_svcs = queue_new();
 	op->pending_chrcs = queue_new();
 	op->svcs = queue_new();
+	op->ext_prop_desc = queue_new();
 	op->client = client;
 	op->complete_func = complete_func;
 	op->failure_func = failure_func;
@@ -604,6 +607,107 @@ failed:
 	return false;
 }
 
+static void ext_prop_write_cb(struct gatt_db_attribute *attrib,
+						int err, void *user_data)
+{
+	struct bt_gatt_client *client = user_data;
+
+	util_debug(client->debug_callback, client->debug_data,
+						"Value set status: %d", err);
+}
+
+static void ext_prop_read_cb(bool success, uint8_t att_ecode,
+					const uint8_t *value, uint16_t length,
+					void *user_data);
+
+static bool read_ext_prop_desc(struct discovery_op *op)
+{
+	struct bt_gatt_client *client = op->client;
+	uint16_t handle;
+	struct gatt_db_attribute *attr;
+
+	attr = queue_peek_head(op->ext_prop_desc);
+	if (!attr)
+		return false;
+
+	handle = gatt_db_attribute_get_handle(attr);
+	bt_gatt_client_read_value(client, handle, ext_prop_read_cb,
+							discovery_op_ref(op),
+							discovery_op_unref);
+
+	return true;
+}
+
+static void ext_prop_read_cb(bool success, uint8_t att_ecode,
+					const uint8_t *value, uint16_t length,
+					void *user_data)
+{
+	struct discovery_op *op = user_data;
+	struct bt_gatt_client *client = op->client;
+	bool discovering;
+	struct gatt_db_attribute *desc_attr = NULL;
+	struct gatt_db_attribute *next_srv;
+	uint16_t start, end;
+
+	util_debug(client->debug_callback, client->debug_data,
+				"Ext. prop value: 0x%04x", (uint16_t)value[0]);
+
+	desc_attr = queue_pop_head(op->ext_prop_desc);
+	if (!desc_attr)
+		goto failed;
+
+	if (!gatt_db_attribute_write(desc_attr, 0, value, length, 0, NULL,
+						ext_prop_write_cb, client))
+		goto failed;
+
+	/* Any other descriptor to read? */
+	if (read_ext_prop_desc(op))
+		return;
+
+	/* Continue with discovery */
+	do {
+		if (!discover_descs(op, &discovering))
+			goto failed;
+
+		if (discovering)
+			return;
+
+		/* Done with the current service */
+		gatt_db_service_set_active(op->cur_svc, true);
+
+		next_srv = queue_pop_head(op->svcs);
+		if (!next_srv)
+			goto done;
+
+		if (!gatt_db_attribute_get_service_handles(next_srv, &start,
+									&end))
+			goto failed;
+
+	} while (start == end);
+
+	/* Move on to the next service */
+	op->cur_svc = next_srv;
+
+	client->discovery_req = bt_gatt_discover_characteristics(client->att,
+							start, end,
+							discover_chrcs_cb,
+							discovery_op_ref(op),
+							discovery_op_unref);
+	if (client->discovery_req)
+		return;
+
+	util_debug(client->debug_callback, client->debug_data,
+				"Failed to start characteristic discovery");
+
+	discovery_op_unref(op);
+
+failed:
+	success = false;
+
+done:
+	discovery_op_complete(op, success, att_ecode);
+}
+
 static void discover_descs_cb(bool success, uint8_t att_ecode,
 						struct bt_gatt_result *result,
 						void *user_data)
@@ -618,6 +722,7 @@ static void discover_descs_cb(bool success, uint8_t att_ecode,
 	char uuid_str[MAX_LEN_UUID_STR];
 	unsigned int desc_count;
 	bool discovering;
+	bt_uuid_t ext_prop_uuid;
 
 	discovery_req_clear(client);
 
@@ -640,6 +745,8 @@ static void discover_descs_cb(bool success, uint8_t att_ecode,
 	util_debug(client->debug_callback, client->debug_data,
 					"Descriptors found: %u", desc_count);
 
+	bt_uuid16_create(&ext_prop_uuid, GATT_CHARAC_EXT_PROPER_UUID);
+
 	while (bt_gatt_iter_next_descriptor(&iter, &handle, u128.data)) {
 		bt_uuid128_create(&uuid, u128);
 
@@ -657,8 +764,15 @@ static void discover_descs_cb(bool success, uint8_t att_ecode,
 
 		if (gatt_db_attribute_get_handle(attr) != handle)
 			goto failed;
+
+		if (!bt_uuid_cmp(&ext_prop_uuid, &uuid))
+			queue_push_tail(op->ext_prop_desc, attr);
 	}
 
+	/* If we got extended prop descriptor, lets read it right away */
+	if (read_ext_prop_desc(op))
+		return;
+
 next:
 	if (!discover_descs(op, &discovering))
 		goto failed;
diff --git a/unit/test-gatt.c b/unit/test-gatt.c
index 6e4dcee..8129719 100644
--- a/unit/test-gatt.c
+++ b/unit/test-gatt.c
@@ -267,6 +267,8 @@ struct context {
 		raw_pdu(0x01, 0x08, 0x18, 0xf0, 0x0a),			\
 		raw_pdu(0x04, 0x16, 0xf0, 0x16, 0xf0),			\
 		raw_pdu(0x05, 0x01, 0x16, 0xf0, 0x00, 0x29),		\
+		raw_pdu(0x0a, 0x16, 0xf0),				\
+		raw_pdu(0x0b, 0x01, 0x00),				\
 		raw_pdu(0x08, 0x01, 0x00, 0x10, 0x00, 0x03, 0x28),	\
 		raw_pdu(0x09, 0x07, 0x02, 0x00, 0xb2, 0x03, 0x00, 0x29,	\
 			0x2a),						\