2018-03-19 12:44:26

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: [PATCH BlueZ 1/2] gatt: Add confirmation callback

From: Luiz Augusto von Dentz <[email protected]>

This replaces indicate flag with confirmation callback to enable
setting custom callback if necessary.
---
src/gatt-database.c | 33 ++++++++++++++++++++-------------
1 file changed, 20 insertions(+), 13 deletions(-)

diff --git a/src/gatt-database.c b/src/gatt-database.c
index 9a33ae7f9..82f376568 100644
--- a/src/gatt-database.c
+++ b/src/gatt-database.c
@@ -956,8 +956,8 @@ struct notify {
uint16_t handle, ccc_handle;
const uint8_t *value;
uint16_t len;
- bool indicate;
- GDBusProxy *proxy;
+ bt_gatt_server_conf_func_t conf;
+ void *user_data;
};

static void conf_cb(void *user_data)
@@ -983,7 +983,7 @@ static void send_notification_to_device(void *data, void *user_data)
if (!ccc)
return;

- if (!ccc->value[0] || (notify->indicate && !(ccc->value[0] & 0x02)))
+ if (!ccc->value[0] || (notify->conf && !(ccc->value[0] & 0x02)))
return;

device = btd_adapter_get_device(notify->database->adapter,
@@ -1003,7 +1003,7 @@ static void send_notification_to_device(void *data, void *user_data)
* TODO: If the device is not connected but bonded, send the
* notification/indication when it becomes connected.
*/
- if (!notify->indicate) {
+ if (!notify->conf) {
DBG("GATT server sending notification");
bt_gatt_server_send_notification(server,
notify->handle, notify->value,
@@ -1013,8 +1013,8 @@ static void send_notification_to_device(void *data, void *user_data)

DBG("GATT server sending indication");
bt_gatt_server_send_indication(server, notify->handle, notify->value,
- notify->len, conf_cb,
- notify->proxy, NULL);
+ notify->len, notify->conf,
+ notify->user_data, NULL);

return;

@@ -1027,10 +1027,16 @@ 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 len, uint16_t ccc_handle,
- bool indicate, GDBusProxy *proxy)
+ bt_gatt_server_conf_func_t conf,
+ void *user_data)
{
struct notify notify;

@@ -1041,8 +1047,8 @@ static void send_notification_to_devices(struct btd_gatt_database *database,
notify.ccc_handle = ccc_handle;
notify.value = value;
notify.len = len;
- notify.indicate = indicate;
- notify.proxy = proxy;
+ notify.conf = conf;
+ notify.user_data = user_data;

queue_foreach(database->device_states, send_notification_to_device,
&notify);
@@ -1073,7 +1079,7 @@ static void send_service_changed(struct btd_gatt_database *database,
put_le16(end, value + 2);

send_notification_to_devices(database, handle, value, sizeof(value),
- ccc_handle, true, NULL);
+ ccc_handle, service_changed_conf, NULL);
}

static void gatt_db_service_added(struct gatt_db_attribute *attrib,
@@ -1948,8 +1954,8 @@ static bool pipe_io_read(struct io *io, void *user_data)
gatt_db_attribute_get_handle(chrc->attrib),
buf, bytes_read,
gatt_db_attribute_get_handle(chrc->ccc),
- chrc->props & BT_GATT_CHRC_PROP_INDICATE,
- chrc->proxy);
+ chrc->props & BT_GATT_CHRC_PROP_INDICATE ?
+ conf_cb : NULL, chrc->proxy);

return true;
}
@@ -2225,7 +2231,8 @@ static void property_changed_cb(GDBusProxy *proxy, const char *name,
gatt_db_attribute_get_handle(chrc->attrib),
value, len,
gatt_db_attribute_get_handle(chrc->ccc),
- chrc->props & BT_GATT_CHRC_PROP_INDICATE, proxy);
+ chrc->props & BT_GATT_CHRC_PROP_INDICATE ?
+ conf_cb : NULL, proxy);
}

static bool database_add_ccc(struct external_service *service,
--
2.14.3



2018-03-22 14:55:50

by Szymon Janc

[permalink] [raw]
Subject: Re: [PATCH BlueZ 1/2] gatt: Add confirmation callback

Hi Luiz,

On Monday, 19 March 2018 13:44:26 CET Luiz Augusto von Dentz wrote:
> From: Luiz Augusto von Dentz <[email protected]>
>
> This replaces indicate flag with confirmation callback to enable
> setting custom callback if necessary.
> ---
> src/gatt-database.c | 33 ++++++++++++++++++++-------------
> 1 file changed, 20 insertions(+), 13 deletions(-)
>
> diff --git a/src/gatt-database.c b/src/gatt-database.c
> index 9a33ae7f9..82f376568 100644
> --- a/src/gatt-database.c
> +++ b/src/gatt-database.c
> @@ -956,8 +956,8 @@ struct notify {
> uint16_t handle, ccc_handle;
> const uint8_t *value;
> uint16_t len;
> - bool indicate;
> - GDBusProxy *proxy;
> + bt_gatt_server_conf_func_t conf;
> + void *user_data;
> };
>
> static void conf_cb(void *user_data)
> @@ -983,7 +983,7 @@ static void send_notification_to_device(void *data, void
> *user_data) if (!ccc)
> return;
>
> - if (!ccc->value[0] || (notify->indicate && !(ccc->value[0] & 0x02)))
> + if (!ccc->value[0] || (notify->conf && !(ccc->value[0] & 0x02)))
> return;
>
> device = btd_adapter_get_device(notify->database->adapter,
> @@ -1003,7 +1003,7 @@ static void send_notification_to_device(void *data,
> void *user_data) * TODO: If the device is not connected but bonded, send
> the
> * notification/indication when it becomes connected.
> */
> - if (!notify->indicate) {
> + if (!notify->conf) {
> DBG("GATT server sending notification");
> bt_gatt_server_send_notification(server,
> notify->handle, notify->value,
> @@ -1013,8 +1013,8 @@ static void send_notification_to_device(void *data,
> void *user_data)
>
> DBG("GATT server sending indication");
> bt_gatt_server_send_indication(server, notify->handle, notify->value,
> - notify->len, conf_cb,
> - notify->proxy, NULL);
> + notify->len, notify->conf,
> + notify->user_data, NULL);
>
> return;
>
> @@ -1027,10 +1027,16 @@ 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 len, uint16_t ccc_handle,
> - bool indicate, GDBusProxy *proxy)
> + bt_gatt_server_conf_func_t conf,
> + void *user_data)
> {
> struct notify notify;
>
> @@ -1041,8 +1047,8 @@ static void send_notification_to_devices(struct
> btd_gatt_database *database, notify.ccc_handle = ccc_handle;
> notify.value = value;
> notify.len = len;
> - notify.indicate = indicate;
> - notify.proxy = proxy;
> + notify.conf = conf;
> + notify.user_data = user_data;
>
> queue_foreach(database->device_states, send_notification_to_device,
> &notify);
> @@ -1073,7 +1079,7 @@ static void send_service_changed(struct
> btd_gatt_database *database, put_le16(end, value + 2);
>
> send_notification_to_devices(database, handle, value, sizeof(value),
> - ccc_handle, true, NULL);
> + ccc_handle, service_changed_conf, NULL);
> }
>
> static void gatt_db_service_added(struct gatt_db_attribute *attrib,
> @@ -1948,8 +1954,8 @@ static bool pipe_io_read(struct io *io, void
> *user_data) gatt_db_attribute_get_handle(chrc->attrib),
> buf, bytes_read,
> gatt_db_attribute_get_handle(chrc->ccc),
> - chrc->props & BT_GATT_CHRC_PROP_INDICATE,
> - chrc->proxy);
> + chrc->props & BT_GATT_CHRC_PROP_INDICATE ?
> + conf_cb : NULL, chrc->proxy);
>
> return true;
> }
> @@ -2225,7 +2231,8 @@ static void property_changed_cb(GDBusProxy *proxy,
> const char *name, gatt_db_attribute_get_handle(chrc->attrib),
> value, len,
> gatt_db_attribute_get_handle(chrc->ccc),
> - chrc->props & BT_GATT_CHRC_PROP_INDICATE, proxy);
> + chrc->props & BT_GATT_CHRC_PROP_INDICATE ?
> + conf_cb : NULL, proxy);
> }
>
> static bool database_add_ccc(struct external_service *service,

Both patches applied, thanks.

--
pozdrawiam
Szymon Janc



2018-03-19 12:44:27

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: [PATCH BlueZ 2/2] gatt: Properly handle service changes when offline

From: Luiz Augusto von Dentz <[email protected]>

If remote peer is disconnected the indication shall be cached so when
the peer connects again it receives the changes.
---
src/device.c | 9 ++++--
src/gatt-database.c | 89 ++++++++++++++++++++++++++++++++++++++++++++---------
src/gatt-database.h | 2 ++
3 files changed, 83 insertions(+), 17 deletions(-)

diff --git a/src/device.c b/src/device.c
index 7c7196ca1..bf5441543 100644
--- a/src/device.c
+++ b/src/device.c
@@ -4825,8 +4825,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;
@@ -4839,6 +4842,8 @@ static void gatt_server_init(struct btd_device *device, struct gatt_db *db)
error("Failed to initialize bt_gatt_server");

bt_gatt_server_set_debug(device->server, gatt_debug, NULL, NULL);
+
+ btd_gatt_database_att_connected(database, device->att);
}

static bool local_counter(uint32_t *sign_cnt, void *user_data)
@@ -4938,7 +4943,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 82f376568..92d0cd248 100644
--- a/src/gatt-database.c
+++ b/src/gatt-database.c
@@ -155,12 +155,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,
@@ -273,6 +283,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);
}

@@ -951,15 +967,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;
-};
-
static void conf_cb(void *user_data)
{
GDBusProxy *proxy = user_data;
@@ -971,6 +978,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);
+}
+
static void send_notification_to_device(void *data, void *user_data)
{
struct device_state *device_state = data;
@@ -996,6 +1038,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;
}

@@ -1027,13 +1070,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)
@@ -3080,3 +3118,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 0d9106b11..0da33f604 100644
--- 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.14.3