diff mbox series

[BlueZ,v1,3/3] monitor: Allow caching of temporary gatt_db

Message ID 20241209205843.1394081-3-luiz.dentz@gmail.com
State New
Headers show
Series [BlueZ,v1,1/3] shared/gatt-db: Fix possible crash on gatt_db_clone | expand

Commit Message

Luiz Augusto von Dentz Dec. 9, 2024, 8:58 p.m. UTC
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

This fixes the problem of not being able to decode GATT traffic when
reading the traces from a file/offline, the gatt_db would be discarded
upon the first disconnection so it didn't work if the trace contains
multiple connections.

To fix this btmon would remember gatt_db discovered at runtime so even
when there multiple connections the same db would be used.
---
 monitor/att.c    | 61 ++++++++++++++++++++++++++++++++++++++++++++----
 monitor/packet.c |  2 +-
 monitor/packet.h |  2 +-
 3 files changed, 58 insertions(+), 7 deletions(-)
diff mbox series

Patch

diff --git a/monitor/att.c b/monitor/att.c
index 3f41c2bd096f..4358cd7348f7 100644
--- a/monitor/att.c
+++ b/monitor/att.c
@@ -63,6 +63,13 @@  struct att_conn_data {
 	uint16_t mtu;
 };
 
+struct gatt_cache {
+	bdaddr_t id;
+	struct gatt_db *db;
+};
+
+static struct queue *cache_list;
+
 static void print_uuid(const char *label, const void *data, uint16_t size)
 {
 	const char *str;
@@ -397,10 +404,42 @@  static const struct bitfield_data chrc_prop_table[] = {
 	{ }
 };
 
-static void att_conn_data_free(void *data)
+static bool match_cache_id(const void *data, const void *match_data)
+{
+	const struct gatt_cache *cache = data;
+	const bdaddr_t *id = match_data;
+
+	return !bacmp(&cache->id, id);
+}
+
+static void gatt_cache_add(struct packet_conn_data *conn, struct gatt_db *db)
+{
+	struct gatt_cache *cache;
+	bdaddr_t id;
+	uint8_t id_type;
+
+	if (!keys_resolve_identity(conn->dst, id.b, &id_type))
+		bacpy(&id, (bdaddr_t *)conn->dst);
+
+	if (queue_find(cache_list, match_cache_id, &id))
+		return;
+
+	if (!cache_list)
+		cache_list = queue_new();
+
+	cache = new0(struct gatt_cache, 1);
+	bacpy(&cache->id, &id);
+	cache->db = gatt_db_ref(db);
+	queue_push_tail(cache_list, cache);
+}
+
+static void att_conn_data_free(struct packet_conn_data *conn, void *data)
 {
 	struct att_conn_data *att_data = data;
 
+	if (!gatt_db_isempty(att_data->rdb))
+		gatt_cache_add(conn, att_data->rdb);
+
 	gatt_db_unref(att_data->rdb);
 	gatt_db_unref(att_data->ldb);
 	queue_destroy(att_data->reads, free);
@@ -456,20 +495,32 @@  static void load_gatt_db(struct packet_conn_data *conn)
 	char filename[PATH_MAX];
 	char local[18];
 	char peer[18];
-	uint8_t id[6], id_type;
+	bdaddr_t id;
+	uint8_t id_type;
 
 	ba2str((bdaddr_t *)conn->src, local);
 
-	if (keys_resolve_identity(conn->dst, id, &id_type))
-		ba2str((bdaddr_t *)id, peer);
-	else
+	if (keys_resolve_identity(conn->dst, id.b, &id_type)) {
+		ba2str(&id, peer);
+	} else {
+		bacpy(&id, (bdaddr_t *)conn->dst);
 		ba2str((bdaddr_t *)conn->dst, peer);
+	}
 
 	create_filename(filename, PATH_MAX, "/%s/attributes", local);
 	gatt_load_db(data->ldb, filename, &data->ldb_mtim);
 
 	create_filename(filename, PATH_MAX, "/%s/cache/%s", local, peer);
 	gatt_load_db(data->rdb, filename, &data->rdb_mtim);
+
+	/* If rdb cannot be loaded from file try local cache */
+	if (gatt_db_isempty(data->rdb)) {
+		struct gatt_cache *cache;
+
+		cache = queue_find(cache_list, match_cache_id, &id);
+		if (cache)
+			data->rdb = cache->db;
+	}
 }
 
 static struct gatt_db *get_db(const struct l2cap_frame *frame, bool rsp)
diff --git a/monitor/packet.c b/monitor/packet.c
index f1a42925a8fc..6a2767ae39b3 100644
--- a/monitor/packet.c
+++ b/monitor/packet.c
@@ -199,7 +199,7 @@  static struct packet_conn_data *release_handle(uint16_t handle)
 
 		if (conn->handle == handle) {
 			if (conn->destroy)
-				conn->destroy(conn->data);
+				conn->destroy(conn, conn->data);
 
 			queue_destroy(conn->tx_q, free);
 			queue_destroy(conn->chan_q, free);
diff --git a/monitor/packet.h b/monitor/packet.h
index 856f74f4db16..964b9a7219fa 100644
--- a/monitor/packet.h
+++ b/monitor/packet.h
@@ -50,7 +50,7 @@  struct packet_conn_data {
 	struct queue *chan_q;
 	struct packet_latency tx_l;
 	void     *data;
-	void     (*destroy)(void *data);
+	void     (*destroy)(struct packet_conn_data *conn, void *data);
 };
 
 struct packet_conn_data *packet_get_conn_data(uint16_t handle);