From abe018f6375b71a2a273a4c05bc4b0df7c11f2bc Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Mon, 19 Mar 2018 14:44:27 +0200 Subject: [PATCH] gatt: Properly handle service changes when offline If remote peer is disconnected the indication shall be cached so when the peer connects again it receives the changes. Change-Id: Ic887ae4f56fdd80efa998e12f6d42f018ad7a6b3 Signed-off-by: Amit Purwar --- src/device.c | 8 +++-- src/gatt-database.c | 89 ++++++++++++++++++++++++++++++++++++++++++++--------- src/gatt-database.h | 2 ++ 3 files changed, 82 insertions(+), 17 deletions(-) diff --git a/src/device.c b/src/device.c index 5b7c0b9..5321f6e 100644 --- a/src/device.c +++ b/src/device.c @@ -7054,8 +7054,11 @@ static void gatt_client_init(struct btd_device *device) btd_gatt_client_connected(device->client_dbus); } -static void gatt_server_init(struct btd_device *device, struct gatt_db *db) +static void gatt_server_init(struct btd_device *device, + struct btd_gatt_database *database) { + struct gatt_db *db = btd_gatt_database_get_db(database); + if (!db) { error("No local GATT database exists for this adapter"); return; @@ -7077,6 +7080,7 @@ static void gatt_server_init(struct btd_device *device, struct gatt_db *db) return; } #endif + btd_gatt_database_att_connected(database, device->att); } static bool local_counter(uint32_t *sign_cnt, void *user_data) @@ -7225,7 +7229,7 @@ bool device_attach_att(struct btd_device *dev, GIOChannel *io) dstaddr); gatt_client_init(dev); - gatt_server_init(dev, btd_gatt_database_get_db(database)); + gatt_server_init(dev, database); /* * Remove the device from the connect_list and give the passive diff --git a/src/gatt-database.c b/src/gatt-database.c index f704f3c..2ba6f15 100644 --- a/src/gatt-database.c +++ b/src/gatt-database.c @@ -156,12 +156,22 @@ struct pending_op { struct iovec data; }; +struct notify { + struct btd_gatt_database *database; + uint16_t handle, ccc_handle; + uint8_t *value; + uint16_t len; + bt_gatt_server_conf_func_t conf; + void *user_data; +}; + struct device_state { struct btd_gatt_database *db; bdaddr_t bdaddr; uint8_t bdaddr_type; unsigned int disc_id; struct queue *ccc_states; + struct notify *pending; }; typedef uint8_t (*btd_gatt_database_ccc_write_t) (struct bt_att *att, @@ -284,6 +294,12 @@ static void device_state_free(void *data) struct device_state *state = data; queue_destroy(state->ccc_states, free); + + if (state->pending) { + free(state->pending->value); + free(state->pending); + } + free(state); } @@ -1132,15 +1148,6 @@ static void register_core_services(struct btd_gatt_database *database) populate_gatt_service(database); } -struct notify { - struct btd_gatt_database *database; - uint16_t handle, ccc_handle; - const uint8_t *value; - uint16_t len; - bt_gatt_server_conf_func_t conf; - void *user_data; -}; - #ifdef TIZEN_FEATURE_BLUEZ_MODIFY struct notify_indicate { struct btd_gatt_database *database; @@ -1207,6 +1214,41 @@ static void conf_cb(void *user_data) } +static void service_changed_conf(void *user_data) +{ + DBG(""); +} + +static void state_set_pending(struct device_state *state, struct notify *notify) +{ + uint16_t start, end, old_start, old_end; + + if (notify->conf != service_changed_conf) + return; + + if (state->pending) { + old_start = get_le16(state->pending->value); + old_end = get_le16(state->pending->value + 2); + + start = get_le16(notify->value); + end = get_le16(notify->value + 2); + + if (start < old_start) + put_le16(start, state->pending->value); + + if (end > old_end) + put_le16(end, state->pending->value + 2); + + return; + } + + /* Copy notify contents to pending */ + state->pending = new0(struct notify, 1); + memcpy(state->pending, notify, sizeof(*notify)); + state->pending->value = malloc(notify->len); + memcpy(state->pending->value, notify->value, notify->len); +} + #ifdef TIZEN_FEATURE_BLUEZ_MODIFY static void conf_cb_tizen(void *user_data) { @@ -1358,6 +1400,7 @@ static void send_notification_to_device(void *data, void *user_data) if (!server) { if (!device_is_paired(device, device_state->bdaddr_type)) goto remove; + state_set_pending(device_state, notify); return; } @@ -1389,13 +1432,8 @@ remove: } } -static void service_changed_conf(void *user_data) -{ - DBG(""); -} - static void send_notification_to_devices(struct btd_gatt_database *database, - uint16_t handle, const uint8_t *value, + uint16_t handle, uint8_t *value, uint16_t len, uint16_t ccc_handle, bt_gatt_server_conf_func_t conf, void *user_data) @@ -3708,3 +3746,24 @@ struct gatt_db *btd_gatt_database_get_db(struct btd_gatt_database *database) return database->db; } + +void btd_gatt_database_att_connected(struct btd_gatt_database *database, + struct bt_att *att) +{ + struct device_state *state; + bdaddr_t bdaddr; + uint8_t bdaddr_type; + + if (!get_dst_info(att, &bdaddr, &bdaddr_type)) + return; + + state = find_device_state(database, &bdaddr, bdaddr_type); + if (!state || !state->pending) + return; + + send_notification_to_device(state, state->pending); + + free(state->pending->value); + free(state->pending); + state->pending = NULL; +} diff --git a/src/gatt-database.h b/src/gatt-database.h index 0d9106b..0da33f6 100755 --- a/src/gatt-database.h +++ b/src/gatt-database.h @@ -23,3 +23,5 @@ struct btd_gatt_database *btd_gatt_database_new(struct btd_adapter *adapter); void btd_gatt_database_destroy(struct btd_gatt_database *database); struct gatt_db *btd_gatt_database_get_db(struct btd_gatt_database *database); +void btd_gatt_database_att_connected(struct btd_gatt_database *database, + struct bt_att *att); -- 2.7.4