Linux-Bluetooth Archive on lore.kernel.org
 help / color / Atom feed
From: Luiz Augusto von Dentz <luiz.dentz@gmail.com>
To: linux-bluetooth@vger.kernel.org
Subject: [PATCH BlueZ 13/15] shared/gatt-client: Read database hash if available
Date: Tue, 29 Jan 2019 15:26:32 +0200
Message-ID: <20190129132634.28786-13-luiz.dentz@gmail.com> (raw)
In-Reply-To: <20190129132634.28786-1-luiz.dentz@gmail.com>

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

This reads the database hash if available and compares to the existing
value, if it matches consider the discovery is completed.
---
 src/shared/gatt-client.c | 177 +++++++++++++++++++++++++++++++++------
 1 file changed, 152 insertions(+), 25 deletions(-)

diff --git a/src/shared/gatt-client.c b/src/shared/gatt-client.c
index 3c2aa293b..d5f9b1294 100644
--- a/src/shared/gatt-client.c
+++ b/src/shared/gatt-client.c
@@ -325,6 +325,7 @@ struct discovery_op {
 	struct queue *pending_chrcs;
 	struct queue *ext_prop_desc;
 	struct gatt_db_attribute *cur_svc;
+	struct gatt_db_attribute *hash;
 	bool success;
 	uint16_t start;
 	uint16_t end;
@@ -349,11 +350,19 @@ static void discovery_op_free(struct discovery_op *op)
 	free(op);
 }
 
+static bool read_db_hash(struct discovery_op *op);
+
 static void discovery_op_complete(struct discovery_op *op, bool success,
 								uint8_t err)
 {
 	const struct queue_entry *svc;
 
+	op->success = success;
+
+	/* Read database hash if discovery has been successful */
+	if (success && read_db_hash(op))
+		return;
+
 	/*
 	 * Unregister remove callback so it is not called when clearing unused
 	 * range.
@@ -380,7 +389,6 @@ static void discovery_op_complete(struct discovery_op *op, bool success,
 	if (op->last != UINT16_MAX)
 		gatt_db_clear_range(op->client->db, op->last + 1, UINT16_MAX);
 
-	op->success = success;
 	op->complete_func(op, success, err);
 }
 
@@ -1249,6 +1257,139 @@ static void notify_client_ready(struct bt_gatt_client *client, bool success,
 	bt_gatt_client_unref(client);
 }
 
+static void discover_all(struct discovery_op *op)
+{
+	struct bt_gatt_client *client = op->client;
+
+	client->discovery_req = bt_gatt_discover_all_primary_services(
+							client->att, NULL,
+							discover_primary_cb,
+							discovery_op_ref(op),
+							discovery_op_unref);
+	if (client->discovery_req)
+		return;
+
+	util_debug(client->debug_callback, client->debug_data,
+			"Failed to initiate primary service discovery");
+
+	client->in_init = false;
+	notify_client_ready(client, false, BT_ATT_ERROR_UNLIKELY);
+
+	discovery_op_unref(op);
+}
+
+static void db_hash_write_value_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 db_hash_read_value_cb(struct gatt_db_attribute *attrib,
+						int err, const uint8_t *value,
+						size_t length, void *user_data)
+{
+	const uint8_t **hash = user_data;
+
+	if (err || (length != 16))
+		return;
+
+	*hash = value;
+}
+
+static void db_hash_read_cb(bool success, uint8_t att_ecode,
+						struct bt_gatt_result *result,
+						void *user_data)
+{
+	struct discovery_op *op = user_data;
+	struct bt_gatt_client *client = op->client;
+	const uint8_t *hash = NULL, *value;
+	uint16_t len, handle;
+	struct bt_gatt_iter iter;
+
+	if (!success)
+		goto discover;
+
+	bt_gatt_iter_init(&iter, result);
+	bt_gatt_iter_next_read_by_type(&iter, &handle, &len, &value);
+
+	util_debug(client->debug_callback, client->debug_data,
+				"DB Hash found: handle 0x%04x length 0x%04x",
+				handle, len);
+
+	if (len != 16)
+		goto discover;
+
+	/* Read stored value in the db */
+	gatt_db_attribute_read(op->hash, 0, BT_ATT_OP_READ_REQ, NULL,
+					db_hash_read_value_cb, &hash);
+
+	/* Check if the has has changed since last time */
+	if (hash && !memcmp(hash, value, len)) {
+		util_debug(client->debug_callback, client->debug_data,
+				"DB Hash match: skipping discovery");
+		queue_remove_all(op->pending_svcs, NULL, NULL, NULL);
+		discovery_op_complete(op, true, 0);
+		return;
+	}
+
+	util_debug(client->debug_callback, client->debug_data,
+						"DB Hash value:");
+	util_hexdump(' ', value, len, client->debug_callback,
+						client->debug_data);
+
+	/* Store the new hash in the db */
+	gatt_db_attribute_write(op->hash, 0, value, len, 0, NULL,
+					db_hash_write_value_cb, client);
+
+discover:
+	if (!op->success) {
+		discover_all(op);
+		return;
+	}
+
+	discovery_op_complete(op, true, 0);
+}
+
+static void get_first_attribute(struct gatt_db_attribute *attrib,
+								void *user_data)
+{
+	struct gatt_db_attribute **stored = user_data;
+
+	if (*stored)
+		return;
+
+	*stored = attrib;
+}
+
+static bool read_db_hash(struct discovery_op *op)
+{
+	struct bt_gatt_client *client = op->client;
+	bt_uuid_t uuid;
+
+	/* Check if hash was already read */
+	if (op->hash)
+		return false;
+
+	bt_uuid16_create(&uuid, GATT_CHARAC_DB_HASH);
+	gatt_db_find_by_type(client->db, 0x0001, 0xffff, &uuid,
+						get_first_attribute, &op->hash);
+	if (!op->hash)
+		return false;
+
+	if (!bt_gatt_read_by_type(client->att, 0x0001, 0xffff, &uuid,
+							db_hash_read_cb,
+							discovery_op_ref(op),
+							discovery_op_unref)) {
+		discovery_op_unref(op);
+		return false;
+	}
+
+	return true;
+}
+
 static void exchange_mtu_cb(bool success, uint8_t att_ecode, void *user_data)
 {
 	struct discovery_op *op = user_data;
@@ -1282,21 +1423,12 @@ static void exchange_mtu_cb(bool success, uint8_t att_ecode, void *user_data)
 					bt_att_get_mtu(client->att));
 
 discover:
-	client->discovery_req = bt_gatt_discover_all_primary_services(
-							client->att, NULL,
-							discover_primary_cb,
-							discovery_op_ref(op),
-							discovery_op_unref);
-	if (client->discovery_req)
+	if (read_db_hash(op)) {
+		op->success = false;
 		return;
+	}
 
-	util_debug(client->debug_callback, client->debug_data,
-			"Failed to initiate primary service discovery");
-
-	client->in_init = false;
-	notify_client_ready(client, false, att_ecode);
-
-	discovery_op_unref(op);
+	discover_all(op);
 }
 
 struct service_changed_op {
@@ -1491,17 +1623,6 @@ static unsigned int register_notify(struct bt_gatt_client *client,
 	return notify_data->id;
 }
 
-static void get_first_attribute(struct gatt_db_attribute *attrib,
-								void *user_data)
-{
-	struct gatt_db_attribute **stored = user_data;
-
-	if (*stored)
-		return;
-
-	*stored = attrib;
-}
-
 static void service_changed_register_cb(uint16_t att_ecode, void *user_data)
 {
 	bool success;
@@ -1747,6 +1868,11 @@ static bool gatt_client_init(struct bt_gatt_client *client, uint16_t mtu)
 	return true;
 
 discover:
+	if (read_db_hash(op)) {
+		op->success = false;
+		goto done;
+	}
+
 	client->discovery_req = bt_gatt_discover_all_primary_services(
 							client->att, NULL,
 							discover_primary_cb,
@@ -1757,6 +1883,7 @@ discover:
 		return false;
 	}
 
+done:
 	client->in_init = true;
 	return true;
 }
-- 
2.17.2


  parent reply index

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-01-29 13:26 [PATCH BlueZ 01/15] shared/crypto: Add bt_crypto_gatt_hash Luiz Augusto von Dentz
2019-01-29 13:26 ` [PATCH BlueZ 02/15] unit/test-crypto: Add test for bt_crypto_gatt_hash Luiz Augusto von Dentz
2019-01-29 13:26 ` [PATCH BlueZ 03/15] lib/uuid: Introduce definition for GATT caching attributes Luiz Augusto von Dentz
2019-01-29 13:26 ` [PATCH BlueZ 04/15] shared/util: Add decoding support " Luiz Augusto von Dentz
2019-01-29 13:26 ` [PATCH BlueZ 05/15] shared/att-types: Add errors introduced by GATT caching Luiz Augusto von Dentz
2019-01-29 13:26 ` [PATCH BlueZ 06/15] monitor: Decode GATT Caching errors Luiz Augusto von Dentz
2019-01-29 13:26 ` [PATCH BlueZ 07/15] shared/gatt-db: Introduce Database Hash Luiz Augusto von Dentz
2019-01-29 13:26 ` [PATCH BlueZ 08/15] shared/gatt-db: Generate database hash Luiz Augusto von Dentz
2019-01-29 13:26 ` [PATCH BlueZ 09/15] gatt: Add caching support for server Luiz Augusto von Dentz
2019-01-29 13:26 ` [PATCH BlueZ 10/15] shared/gatt-db: Add gatt_db_set_authorize Luiz Augusto von Dentz
2019-01-29 13:26 ` [PATCH BlueZ 11/15] shared/gatt-server: Add bt_gatt_server_set_authorize Luiz Augusto von Dentz
2019-01-29 13:26 ` [PATCH BlueZ 12/15] gatt: Implement Robust Caching handling for server Luiz Augusto von Dentz
2019-01-29 13:26 ` Luiz Augusto von Dentz [this message]
2019-01-29 13:26 ` [PATCH BlueZ 14/15] shared/gatt-client: Write Client Features Luiz Augusto von Dentz
2019-01-29 13:26 ` [PATCH BlueZ 15/15] device: Store Database Hash on storage Luiz Augusto von Dentz
2019-02-06 11:49 ` [PATCH BlueZ 01/15] shared/crypto: Add bt_crypto_gatt_hash Luiz Augusto von Dentz

Reply instructions:

You may reply publically to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20190129132634.28786-13-luiz.dentz@gmail.com \
    --to=luiz.dentz@gmail.com \
    --cc=linux-bluetooth@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link

Linux-Bluetooth Archive on lore.kernel.org

Archives are clonable:
	git clone --mirror https://lore.kernel.org/linux-bluetooth/0 linux-bluetooth/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 linux-bluetooth linux-bluetooth/ https://lore.kernel.org/linux-bluetooth \
		linux-bluetooth@vger.kernel.org linux-bluetooth@archiver.kernel.org
	public-inbox-index linux-bluetooth


Newsgroup available over NNTP:
	nntp://nntp.lore.kernel.org/org.kernel.vger.linux-bluetooth


AGPL code for this site: git clone https://public-inbox.org/ public-inbox