From: Luiz Augusto von Dentz <luiz.dentz@gmail.com>
To: linux-bluetooth@vger.kernel.org
Subject: [PATCH BlueZ 2/3] gatt: Clear subscriptions for device not paired
Date: Mon, 23 Oct 2017 14:17:22 +0300 [thread overview]
Message-ID: <20171023111723.20729-2-luiz.dentz@gmail.com> (raw)
In-Reply-To: <20171023111723.20729-1-luiz.dentz@gmail.com>
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
If the device is no longer valid or is not considered bonded anymore
clear its CCC states before removing otherwise application may continue
to notify when there are no devices listening.
---
src/gatt-database.c | 155 ++++++++++++++++++++++++++++++++++------------------
1 file changed, 103 insertions(+), 52 deletions(-)
diff --git a/src/gatt-database.c b/src/gatt-database.c
index 47304704a..6784998c3 100644
--- a/src/gatt-database.c
+++ b/src/gatt-database.c
@@ -150,8 +150,10 @@ struct pending_op {
};
struct device_state {
+ struct btd_gatt_database *db;
bdaddr_t bdaddr;
uint8_t bdaddr_type;
+ unsigned int disc_id;
struct queue *ccc_states;
};
@@ -245,12 +247,14 @@ static struct ccc_state *find_ccc_state(struct device_state *dev_state,
UINT_TO_PTR(handle));
}
-static struct device_state *device_state_create(bdaddr_t *bdaddr,
+static struct device_state *device_state_create(struct btd_gatt_database *db,
+ bdaddr_t *bdaddr,
uint8_t bdaddr_type)
{
struct device_state *dev_state;
dev_state = new0(struct device_state, 1);
+ dev_state->db = db;
dev_state->ccc_states = queue_new();
bacpy(&dev_state->bdaddr, bdaddr);
dev_state->bdaddr_type = bdaddr_type;
@@ -258,36 +262,117 @@ static struct device_state *device_state_create(bdaddr_t *bdaddr,
return dev_state;
}
+static void device_state_free(void *data)
+{
+ struct device_state *state = data;
+
+ queue_destroy(state->ccc_states, free);
+ free(state);
+}
+
+static void clear_ccc_state(void *data, void *user_data)
+{
+ struct ccc_state *ccc = data;
+ struct btd_gatt_database *db = user_data;
+ struct ccc_cb_data *ccc_cb;
+
+ if (!ccc->value[0])
+ return;
+
+ ccc_cb = queue_find(db->ccc_callbacks, ccc_cb_match_handle,
+ UINT_TO_PTR(ccc->handle));
+ if (!ccc_cb)
+ return;
+
+ ccc_cb->callback(NULL, 0, ccc_cb->user_data);
+}
+
+static void att_disconnected(int err, void *user_data)
+{
+ struct device_state *state = user_data;
+ struct btd_device *device;
+
+ DBG("");
+
+ state->disc_id = 0;
+
+ device = btd_adapter_get_device(state->db->adapter, &state->bdaddr,
+ state->bdaddr_type);
+ if (!device)
+ goto remove;
+
+ if (device_is_paired(device, state->bdaddr_type))
+ return;
+
+remove:
+ /* Remove device state if device no longer exists or is not paired */
+ if (queue_remove(state->db->device_states, state)) {
+ queue_foreach(state->ccc_states, clear_ccc_state, state->db);
+ device_state_free(state);
+ }
+}
+
+static bool get_dst_info(struct bt_att *att, bdaddr_t *dst, uint8_t *dst_type)
+{
+ GIOChannel *io = NULL;
+ GError *gerr = NULL;
+
+ io = g_io_channel_unix_new(bt_att_get_fd(att));
+ if (!io)
+ return false;
+
+ bt_io_get(io, &gerr, BT_IO_OPT_DEST_BDADDR, dst,
+ BT_IO_OPT_DEST_TYPE, dst_type,
+ BT_IO_OPT_INVALID);
+ if (gerr) {
+ error("gatt: bt_io_get: %s", gerr->message);
+ g_error_free(gerr);
+ g_io_channel_unref(io);
+ return false;
+ }
+
+ g_io_channel_unref(io);
+ return true;
+}
+
static struct device_state *get_device_state(struct btd_gatt_database *database,
- bdaddr_t *bdaddr,
- uint8_t bdaddr_type)
+ struct bt_att *att)
{
struct device_state *dev_state;
+ bdaddr_t bdaddr;
+ uint8_t bdaddr_type;
+
+ if (!get_dst_info(att, &bdaddr, &bdaddr_type))
+ return NULL;
/*
* Find and return a device state. If a matching state doesn't exist,
* then create a new one.
*/
- dev_state = find_device_state(database, bdaddr, bdaddr_type);
+ dev_state = find_device_state(database, &bdaddr, bdaddr_type);
if (dev_state)
- return dev_state;
+ goto done;
- dev_state = device_state_create(bdaddr, bdaddr_type);
+ dev_state = device_state_create(database, &bdaddr, bdaddr_type);
queue_push_tail(database->device_states, dev_state);
+done:
+ dev_state->disc_id = bt_att_register_disconnect(att, att_disconnected,
+ dev_state, NULL);
+
return dev_state;
}
static struct ccc_state *get_ccc_state(struct btd_gatt_database *database,
- bdaddr_t *bdaddr,
- uint8_t bdaddr_type,
- uint16_t handle)
+ struct bt_att *att, uint16_t handle)
{
struct device_state *dev_state;
struct ccc_state *ccc;
- dev_state = get_device_state(database, bdaddr, bdaddr_type);
+ dev_state = get_device_state(database, att);
+ if (!dev_state)
+ return NULL;
ccc = find_ccc_state(dev_state, handle);
if (ccc)
@@ -300,14 +385,6 @@ static struct ccc_state *get_ccc_state(struct btd_gatt_database *database,
return ccc;
}
-static void device_state_free(void *data)
-{
- struct device_state *state = data;
-
- queue_destroy(state->ccc_states, free);
- free(state);
-}
-
static void cancel_pending_read(void *data)
{
struct pending_op *op = data;
@@ -690,29 +767,6 @@ static void populate_gap_service(struct btd_gatt_database *database)
gatt_db_service_set_active(service, true);
}
-static bool get_dst_info(struct bt_att *att, bdaddr_t *dst, uint8_t *dst_type)
-{
- GIOChannel *io = NULL;
- GError *gerr = NULL;
-
- io = g_io_channel_unix_new(bt_att_get_fd(att));
- if (!io)
- return false;
-
- bt_io_get(io, &gerr, BT_IO_OPT_DEST_BDADDR, dst,
- BT_IO_OPT_DEST_TYPE, dst_type,
- BT_IO_OPT_INVALID);
- if (gerr) {
- error("gatt: bt_io_get: %s", gerr->message);
- g_error_free(gerr);
- g_io_channel_unref(io);
- return false;
- }
-
- g_io_channel_unref(io);
- return true;
-}
-
static void gatt_ccc_read_cb(struct gatt_db_attribute *attrib,
unsigned int id, uint16_t offset,
uint8_t opcode, struct bt_att *att,
@@ -724,8 +778,6 @@ static void gatt_ccc_read_cb(struct gatt_db_attribute *attrib,
uint8_t ecode = 0;
const uint8_t *value = NULL;
size_t len = 0;
- bdaddr_t bdaddr;
- uint8_t bdaddr_type;
handle = gatt_db_attribute_get_handle(attrib);
@@ -736,13 +788,12 @@ static void gatt_ccc_read_cb(struct gatt_db_attribute *attrib,
goto done;
}
- if (!get_dst_info(att, &bdaddr, &bdaddr_type)) {
+ ccc = get_ccc_state(database, att, handle);
+ if (!ccc) {
ecode = BT_ATT_ERROR_UNLIKELY;
goto done;
}
- ccc = get_ccc_state(database, &bdaddr, bdaddr_type, handle);
-
len = 2 - offset;
value = len ? &ccc->value[offset] : NULL;
@@ -761,8 +812,6 @@ static void gatt_ccc_write_cb(struct gatt_db_attribute *attrib,
struct ccc_cb_data *ccc_cb;
uint16_t handle;
uint8_t ecode = 0;
- bdaddr_t bdaddr;
- uint8_t bdaddr_type;
handle = gatt_db_attribute_get_handle(attrib);
@@ -778,13 +827,12 @@ static void gatt_ccc_write_cb(struct gatt_db_attribute *attrib,
goto done;
}
- if (!get_dst_info(att, &bdaddr, &bdaddr_type)) {
+ ccc = get_ccc_state(database, att, handle);
+ if (!ccc) {
ecode = BT_ATT_ERROR_UNLIKELY;
goto done;
}
- ccc = get_ccc_state(database, &bdaddr, bdaddr_type, handle);
-
ccc_cb = queue_find(database->ccc_callbacks, ccc_cb_match_handle,
UINT_TO_PTR(gatt_db_attribute_get_handle(attrib)));
if (!ccc_cb) {
@@ -940,8 +988,11 @@ static void send_notification_to_device(void *data, void *user_data)
remove:
/* Remove device state if device no longer exists or is not paired */
- if (queue_remove(notify->database->device_states, device_state))
+ if (queue_remove(notify->database->device_states, device_state)) {
+ queue_foreach(device_state->ccc_states, clear_ccc_state,
+ notify->database);
device_state_free(device_state);
+ }
}
static void send_notification_to_devices(struct btd_gatt_database *database,
--
2.13.6
next prev parent reply other threads:[~2017-10-23 11:17 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2017-10-23 11:17 [PATCH BlueZ 1/3] shared/att: Fix crash when calling disconnect handlers Luiz Augusto von Dentz
2017-10-23 11:17 ` Luiz Augusto von Dentz [this message]
2017-10-23 20:26 ` [PATCH BlueZ 2/3] gatt: Clear subscriptions for device not paired Yunhan Wang
2017-10-23 20:29 ` Luiz Augusto von Dentz
2017-10-23 20:59 ` Yunhan Wang
2017-10-24 8:10 ` Luiz Augusto von Dentz
2017-10-25 7:58 ` Yunhan Wang
2017-10-25 13:27 ` Luiz Augusto von Dentz
2017-10-30 21:44 ` Yunhan Wang
2017-11-02 17:45 ` Yunhan Wang
2017-11-02 18:07 ` Luiz Augusto von Dentz
2017-10-23 11:17 ` [PATCH BlueZ 3/3] test/example-gatt-server: Don't change measuments if not notifying Luiz Augusto von Dentz
Reply instructions:
You may reply publicly 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=20171023111723.20729-2-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
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).