@@ -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)
@@ -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);
@@ -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);
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(-)