Bluetooth: Disable GATT notifications while disconnected

Once disconnected disable CCC configuration and enabling it back once
reconnected:

bt: bt_gatt_disconnected (0x0010c610): conn 0x0010a1f4
bt: disconnected_cb (0x0010c610): ccc 0x00108e44 reseted
Disconnected
Connected
bt: bt_gatt_connected (0x0010c610): conn 0x0010a1f4
bt: gatt_ccc_changed (0x0010c610): ccc 0x00108e44 value 0x0001

Change-Id: Ia4ac6793176f80ea9c6f255a4d151f9080660b0d
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
This commit is contained in:
Luiz Augusto von Dentz 2015-06-17 13:31:00 +03:00 committed by Anas Nashif
commit 168446d058
3 changed files with 100 additions and 0 deletions

View file

@ -608,4 +608,10 @@ int bt_gatt_attr_read_cep(const bt_addr_le_t *peer,
*/
void bt_gatt_notify(uint16_t handle, const void *data, size_t len);
/*! @brief connected callback */
void bt_gatt_connected(struct bt_conn *conn);
/*! @brief disconnected callback */
void bt_gatt_disconnected(struct bt_conn *conn);
#endif /* __BT_GATT_H */

View file

@ -1212,6 +1212,7 @@ static void bt_att_connected(struct bt_conn *conn)
att->conn = conn;
conn->att = att;
att->mtu = BT_ATT_DEFAULT_LE_MTU;
bt_gatt_connected(conn);
return;
}
}
@ -1231,6 +1232,7 @@ static void bt_att_disconnected(struct bt_conn *conn)
conn->att = NULL;
memset(att, 0, sizeof(*att));
bt_gatt_disconnected(conn);
}
void bt_att_init(void)

View file

@ -219,6 +219,8 @@ static void gatt_ccc_changed(struct _bt_gatt_ccc *ccc)
}
}
BT_DBG("ccc %p value 0x%04x\n", ccc, value);
if (value != ccc->value) {
ccc->value = value;
ccc->cfg_changed(value);
@ -368,3 +370,93 @@ void bt_gatt_notify(uint16_t handle, const void *data, size_t len)
bt_gatt_foreach_attr(handle, 0xffff, notify_cb, &nfy);
}
static uint8_t connected_cb(const struct bt_gatt_attr *attr, void *user_data)
{
struct bt_conn *conn = user_data;
struct _bt_gatt_ccc *ccc;
size_t i;
/* Check attribute user_data must be of type struct _bt_gatt_ccc */
if (attr->write != bt_gatt_attr_write_ccc) {
return BT_GATT_ITER_CONTINUE;
}
ccc = attr->user_data;
/* If already enabled skip */
if (ccc->value) {
return BT_GATT_ITER_CONTINUE;
}
for (i = 0; i < ccc->cfg_len; i++) {
/* Ignore configuration for different peer */
if (bt_addr_le_cmp(&conn->dst, &ccc->cfg[i].peer)) {
continue;
}
if (ccc->cfg[i].value) {
gatt_ccc_changed(ccc);
return BT_GATT_ITER_CONTINUE;
}
}
return BT_GATT_ITER_CONTINUE;
}
void bt_gatt_connected(struct bt_conn *conn)
{
BT_DBG("conn %p\n", conn);
bt_gatt_foreach_attr(0x0001, 0xffff, connected_cb, conn);
}
static uint8_t disconnected_cb(const struct bt_gatt_attr *attr, void *user_data)
{
struct bt_conn *conn = user_data;
struct _bt_gatt_ccc *ccc;
size_t i;
/* Check attribute user_data must be of type struct _bt_gatt_ccc */
if (attr->write != bt_gatt_attr_write_ccc) {
return BT_GATT_ITER_CONTINUE;
}
ccc = attr->user_data;
/* If already disabled skip */
if (!ccc->value) {
return BT_GATT_ITER_CONTINUE;
}
for (i = 0; i < ccc->cfg_len; i++) {
/* Ignore configurations with disabled value */
if (!ccc->cfg[i].value) {
continue;
}
if (bt_addr_le_cmp(&conn->dst, &ccc->cfg[i].peer)) {
struct bt_conn *tmp;
/* Skip if there is another peer connected */
tmp = bt_conn_lookup_addr_le(&ccc->cfg[i].peer);
if (tmp) {
bt_conn_put(tmp);
return BT_GATT_ITER_CONTINUE;
}
}
}
/* Reset value while disconnected */
memset(&ccc->value, 0, sizeof(ccc->value));
ccc->cfg_changed(ccc->value);
BT_DBG("ccc %p reseted\n", ccc);
return BT_GATT_ITER_CONTINUE;
}
void bt_gatt_disconnected(struct bt_conn *conn)
{
BT_DBG("conn %p\n", conn);
bt_gatt_foreach_attr(0x0001, 0xffff, disconnected_cb, conn);
}