Skip to content

Commit daac1fa

Browse files
Vudentzjhedberg
authored andcommitted
Bluetooth: GATT: Implement Robust Caching
This implement Robust Caching which is mandatory when Database Hash and Service changed Characteristics are supported. Signed-off-by: Luiz Augusto von Dentz <[email protected]>
1 parent a3bca71 commit daac1fa

File tree

3 files changed

+125
-10
lines changed

3 files changed

+125
-10
lines changed

subsys/bluetooth/host/att.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -919,6 +919,10 @@ static u8_t att_read_rsp(struct bt_att *att, u8_t op, u8_t rsp, u16_t handle,
919919
struct bt_conn *conn = att->chan.chan.conn;
920920
struct read_data data;
921921

922+
if (!bt_gatt_change_aware(conn, true)) {
923+
return BT_ATT_ERR_DB_OUT_OF_SYNC;
924+
}
925+
922926
if (!handle) {
923927
return BT_ATT_ERR_INVALID_HANDLE;
924928
}
@@ -1233,6 +1237,10 @@ static u8_t att_write_rsp(struct bt_conn *conn, u8_t req, u8_t rsp,
12331237
{
12341238
struct write_data data;
12351239

1240+
if (!bt_gatt_change_aware(conn, req ? true : false)) {
1241+
return BT_ATT_ERR_DB_OUT_OF_SYNC;
1242+
}
1243+
12361244
if (!handle) {
12371245
return BT_ATT_ERR_INVALID_HANDLE;
12381246
}
@@ -1350,6 +1358,10 @@ static u8_t att_prep_write_rsp(struct bt_att *att, u16_t handle, u16_t offset,
13501358
struct prep_data data;
13511359
struct bt_att_prepare_write_rsp *rsp;
13521360

1361+
if (!bt_gatt_change_aware(conn, true)) {
1362+
return BT_ATT_ERR_DB_OUT_OF_SYNC;
1363+
}
1364+
13531365
if (!handle) {
13541366
return BT_ATT_ERR_INVALID_HANDLE;
13551367
}

subsys/bluetooth/host/gatt.c

Lines changed: 111 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -175,10 +175,21 @@ static void sc_ccc_cfg_changed(const struct bt_gatt_attr *attr,
175175
BT_DBG("value 0x%04x", value);
176176
}
177177

178+
enum {
179+
CF_CHANGE_AWARE, /* Client is changed aware */
180+
CF_OUT_OF_SYNC, /* Client is out of sync */
181+
182+
/* Total number of flags - must be at the end of the enum */
183+
CF_NUM_FLAGS,
184+
};
185+
186+
#define CF_ROBUST_CACHING(_cfg) (_cfg->data[0] & BIT(0))
187+
178188
struct gatt_cf_cfg {
179189
u8_t id;
180190
bt_addr_le_t peer;
181191
u8_t data[1];
192+
ATOMIC_DEFINE(flags, CF_NUM_FLAGS);
182193
};
183194

184195
#if defined(CONFIG_BT_GATT_CACHING)
@@ -216,13 +227,15 @@ static ssize_t cf_read(struct bt_conn *conn, const struct bt_gatt_attr *attr,
216227
static bool cf_set_value(struct gatt_cf_cfg *cfg, const u8_t *value, u16_t len)
217228
{
218229
u16_t i;
230+
u8_t last_byte = 1;
231+
u8_t last_bit = 1;
219232

220233
/* Validate the bits */
221-
for (i = 0; i < len; i++) {
234+
for (i = 0; i < len && i < last_byte; i++) {
222235
u8_t chg_bits = value[i] ^ cfg->data[i];
223236
u8_t bit;
224237

225-
for (bit = 0; bit < 8; bit++) {
238+
for (bit = 0; bit < last_bit; bit++) {
226239
/* A client shall never clear a bit it has set */
227240
if ((BIT(bit) & chg_bits) &&
228241
(BIT(bit) & cfg->data[i])) {
@@ -232,8 +245,8 @@ static bool cf_set_value(struct gatt_cf_cfg *cfg, const u8_t *value, u16_t len)
232245
}
233246

234247
/* Set the bits for each octect */
235-
for (i = 0; i < len; i++) {
236-
cfg->data[i] |= value[i];
248+
for (i = 0; i < len && i < last_byte; i++) {
249+
cfg->data[i] |= value[i] & ((1 << last_bit) - 1);
237250
BT_DBG("byte %u: data 0x%02x value 0x%02x", i, cfg->data[i],
238251
value[i]);
239252
}
@@ -272,6 +285,7 @@ static ssize_t cf_write(struct bt_conn *conn, const struct bt_gatt_attr *attr,
272285
}
273286

274287
bt_addr_le_copy(&cfg->peer, &conn->le.dst);
288+
atomic_set_bit(cfg->flags, CF_CHANGE_AWARE);
275289

276290
return len;
277291
}
@@ -396,6 +410,14 @@ static ssize_t db_hash_read(struct bt_conn *conn,
396410
db_hash_gen();
397411
}
398412

413+
/* BLUETOOTH CORE SPECIFICATION Version 5.1 | Vol 3, Part G page 2347:
414+
* 2.5.2.1 Robust Caching
415+
* A connected client becomes change-aware when...
416+
* The client reads the Database Hash characteristic and then the server
417+
* receives another ATT request from the client.
418+
*/
419+
bt_gatt_change_aware(conn, true);
420+
399421
return bt_gatt_attr_read(conn, attr, buf, len, offset, db_hash,
400422
sizeof(db_hash));
401423
}
@@ -485,6 +507,10 @@ static struct gatt_sc {
485507
static void sc_indicate_rsp(struct bt_conn *conn,
486508
const struct bt_gatt_attr *attr, u8_t err)
487509
{
510+
#if defined(CONFIG_BT_GATT_CACHING)
511+
struct gatt_cf_cfg *cfg;
512+
#endif
513+
488514
BT_DBG("err 0x%02x", err);
489515

490516
atomic_clear_bit(gatt_sc.flags, SC_INDICATE_PENDING);
@@ -494,6 +520,19 @@ static void sc_indicate_rsp(struct bt_conn *conn,
494520
/* Reschedule without any delay since it is waiting already */
495521
k_delayed_work_submit(&gatt_sc.work, K_NO_WAIT);
496522
}
523+
524+
#if defined(CONFIG_BT_GATT_CACHING)
525+
/* BLUETOOTH CORE SPECIFICATION Version 5.1 | Vol 3, Part G page 2347:
526+
* 2.5.2.1 Robust Caching
527+
* A connected client becomes change-aware when...
528+
* The client receives and confirms a Service Changed indication.
529+
*/
530+
cfg = find_cf_cfg(&conn->le.dst);
531+
if (cfg && CF_ROBUST_CACHING(cfg)) {
532+
atomic_set_bit(cfg->flags, CF_CHANGE_AWARE);
533+
BT_DBG("%s change-aware", bt_addr_le_str(&cfg->peer));
534+
}
535+
#endif
497536
}
498537

499538
static void sc_process(struct k_work *work)
@@ -645,6 +684,28 @@ static void sc_indicate(struct gatt_sc *sc, uint16_t start, uint16_t end)
645684
k_delayed_work_submit(&sc->work, SC_TIMEOUT);
646685
}
647686

687+
static void db_changed(void)
688+
{
689+
#if defined(CONFIG_BT_GATT_CACHING)
690+
int i;
691+
692+
k_delayed_work_submit(&db_hash_work, DB_HASH_TIMEOUT);
693+
694+
for (i = 0; i < ARRAY_SIZE(cf_cfg); i++) {
695+
struct gatt_cf_cfg *cfg = &cf_cfg[i];
696+
697+
if (!bt_addr_le_cmp(&cfg->peer, BT_ADDR_LE_ANY)) {
698+
continue;
699+
}
700+
701+
if (CF_ROBUST_CACHING(cfg) &&
702+
atomic_test_and_clear_bit(cfg->flags, CF_CHANGE_AWARE)) {
703+
BT_DBG("%s change-unaware", bt_addr_le_str(&cfg->peer));
704+
}
705+
}
706+
#endif
707+
}
708+
648709
int bt_gatt_service_register(struct bt_gatt_service *svc)
649710
{
650711
int err;
@@ -670,9 +731,7 @@ int bt_gatt_service_register(struct bt_gatt_service *svc)
670731
sc_indicate(&gatt_sc, svc->attrs[0].handle,
671732
svc->attrs[svc->attr_count - 1].handle);
672733

673-
#if defined(CONFIG_BT_GATT_CACHING)
674-
k_delayed_work_submit(&db_hash_work, DB_HASH_TIMEOUT);
675-
#endif /* COFNIG_BT_GATT_CACHING */
734+
db_changed();
676735

677736
return 0;
678737
}
@@ -688,9 +747,7 @@ int bt_gatt_service_unregister(struct bt_gatt_service *svc)
688747
sc_indicate(&gatt_sc, svc->attrs[0].handle,
689748
svc->attrs[svc->attr_count - 1].handle);
690749

691-
#if defined(CONFIG_BT_GATT_CACHING)
692-
k_delayed_work_submit(&db_hash_work, DB_HASH_TIMEOUT);
693-
#endif /* COFNIG_BT_GATT_CACHING */
750+
db_changed();
694751

695752
return 0;
696753
}
@@ -2686,6 +2743,50 @@ void bt_gatt_connected(struct bt_conn *conn)
26862743
#endif /* CONFIG_BT_GATT_CLIENT */
26872744
}
26882745

2746+
bool bt_gatt_change_aware(struct bt_conn *conn, bool req)
2747+
{
2748+
#if defined(CONFIG_BT_GATT_CACHING)
2749+
struct gatt_cf_cfg *cfg;
2750+
2751+
cfg = find_cf_cfg(&conn->le.dst);
2752+
if (!cfg || !CF_ROBUST_CACHING(cfg)) {
2753+
return true;
2754+
}
2755+
2756+
if (atomic_test_bit(cfg->flags, CF_CHANGE_AWARE)) {
2757+
return true;
2758+
}
2759+
2760+
/* BLUETOOTH CORE SPECIFICATION Version 5.1 | Vol 3, Part G page 2350:
2761+
* If a change-unaware client sends an ATT command, the server shall
2762+
* ignore it.
2763+
*/
2764+
if (!req) {
2765+
return false;
2766+
}
2767+
2768+
/* BLUETOOTH CORE SPECIFICATION Version 5.1 | Vol 3, Part G page 2347:
2769+
* 2.5.2.1 Robust Caching
2770+
* A connected client becomes change-aware when...
2771+
* The server sends the client a response with the error code set to
2772+
* Database Out Of Sync and then the server receives another ATT
2773+
* request from the client.
2774+
*/
2775+
if (atomic_test_bit(cfg->flags, CF_OUT_OF_SYNC)) {
2776+
atomic_clear_bit(cfg->flags, CF_OUT_OF_SYNC);
2777+
atomic_set_bit(cfg->flags, CF_CHANGE_AWARE);
2778+
BT_DBG("%s change-aware", bt_addr_le_str(&cfg->peer));
2779+
return true;
2780+
}
2781+
2782+
atomic_set_bit(cfg->flags, CF_OUT_OF_SYNC);
2783+
2784+
return false;
2785+
#else
2786+
return true;
2787+
#endif
2788+
}
2789+
26892790
void bt_gatt_disconnected(struct bt_conn *conn)
26902791
{
26912792
BT_DBG("conn %p", conn);

subsys/bluetooth/host/gatt_internal.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ void bt_gatt_init(void);
1515
void bt_gatt_connected(struct bt_conn *conn);
1616
void bt_gatt_disconnected(struct bt_conn *conn);
1717

18+
bool bt_gatt_change_aware(struct bt_conn *conn, bool req);
19+
1820
int bt_gatt_store_ccc(u8_t id, const bt_addr_le_t *addr);
1921
int bt_gatt_clear_ccc(u8_t id, const bt_addr_le_t *addr);
2022

0 commit comments

Comments
 (0)