Skip to content

Commit eec682f

Browse files
nimble/host: implement robust gatt caching (server side)
Add support for Robust GATT Caching.
1 parent 3bb2671 commit eec682f

File tree

12 files changed

+451
-1
lines changed

12 files changed

+451
-1
lines changed

nimble/host/include/host/ble_att.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,9 @@ struct os_mbuf;
110110
/**Insufficient Resources to complete the request. */
111111
#define BLE_ATT_ERR_INSUFFICIENT_RES 0x11
112112

113+
/**The server requests the client to rediscover the database. */
114+
#define BLE_ATT_ERR_DB_OUT_OF_SYNC 0x12
115+
113116
/**Requested value is not allowed. */
114117
#define BLE_ATT_ERR_VALUE_NOT_ALLOWED 0x13
115118

nimble/host/include/host/ble_store.h

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@ extern "C" {
4848
/** Object type: Client Characteristic Configuration Descriptor. */
4949
#define BLE_STORE_OBJ_TYPE_CCCD 3
5050

51+
/** Object type: Peer database hash. */
52+
#define BLE_STORE_OBJ_TYPE_DB_HASH 4
53+
5154
/** @} */
5255

5356
/**
@@ -154,6 +157,36 @@ struct ble_store_value_cccd {
154157
unsigned value_changed:1;
155158
};
156159

160+
/**
161+
* Used as key for lookups of stored database hash.
162+
* This struct corresponds to the BLE_STORE_OBJ_TYPE_DB_HASH store object
163+
* type.
164+
*/
165+
struct ble_store_key_db_hash {
166+
/**
167+
* Key by peer identity address;
168+
* peer_addr=BLE_ADDR_NONE means don't key off peer.
169+
*/
170+
ble_addr_t peer_addr;
171+
172+
/** Number of results to skip; 0 means retrieve the first match. */
173+
uint8_t idx;
174+
};
175+
176+
/**
177+
* Represents a stored database hash of a peer. This struct
178+
* corresponds to the BLE_STORE_OBJ_TYPE_DB_HASH store object type.
179+
*/
180+
struct ble_store_value_db_hash {
181+
/** The peer address associated with the stored database hash. */
182+
ble_addr_t peer_addr;
183+
/** Flag indicating whether the peer is supporting robust cacheing. */
184+
bool is_cache_supported;
185+
/** Database hash; can be used to determine whether the peer
186+
* is change aware/unaware. */
187+
uint8_t db_hash[16];
188+
};
189+
157190
/**
158191
* Used as a key for store lookups. This union must be accompanied by an
159192
* object type code to indicate which field is valid.
@@ -163,6 +196,8 @@ union ble_store_key {
163196
struct ble_store_key_sec sec;
164197
/** Key for Client Characteristic Configuration Descriptor store lookups. */
165198
struct ble_store_key_cccd cccd;
199+
/** Key for database hash store lookups */
200+
struct ble_store_key_db_hash db_hash;
166201
};
167202

168203
/**
@@ -174,6 +209,8 @@ union ble_store_value {
174209
struct ble_store_value_sec sec;
175210
/** Stored Client Characteristic Configuration Descriptor. */
176211
struct ble_store_value_cccd cccd;
212+
/** Stored database hash. */
213+
struct ble_store_value_db_hash db_hash;
177214
};
178215

179216
/** Represents an event associated with the BLE Store. */
@@ -540,6 +577,22 @@ int ble_store_read_cccd(const struct ble_store_key_cccd *key,
540577
*/
541578
int ble_store_write_cccd(const struct ble_store_value_cccd *value);
542579

580+
///**
581+
// * @brief Writes a database hash to a storage.
582+
// *
583+
// * This function writes database hash value to a storage based on the
584+
// * provided value.
585+
// *
586+
// * @param value A pointer to a `ble_store_value_db_hash`
587+
// * structure representing the database hash
588+
// * to be written to a storage.
589+
// *
590+
// * @return 0 if the database hash was successfully
591+
// * written to a storage;
592+
// * Non-zero on error.
593+
// */
594+
//int ble_store_write_db_hash(const struct ble_store_value_db_hash *value);
595+
543596
/**
544597
* @brief Deletes a Client Characteristic Configuration Descriptor (CCCD) from
545598
* a storage.

nimble/host/services/gatt/include/services/gatt/ble_svc_gatt.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ struct ble_hs_cfg;
3131
#define BLE_SVC_GATT_CHR_SERVICE_CHANGED_UUID16 0x2a05
3232
#define BLE_SVC_GATT_CHR_SERVER_SUPPORTED_FEAT_UUID16 0x2b3a
3333
#define BLE_SVC_GATT_CHR_CLIENT_SUPPORTED_FEAT_UUID16 0x2b29
34+
#define BLE_SVC_GATT_CHR_DATABASE_HASH_UUID16 0x2b2a
3435

3536
uint8_t ble_svc_gatt_get_local_cl_supported_feat(void);
3637
void ble_svc_gatt_changed(uint16_t start_handle, uint16_t end_handle);

nimble/host/services/gatt/src/ble_svc_gatt.c

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
#include "sysinit/sysinit.h"
2323
#include "host/ble_hs.h"
24+
#include "../src/ble_hs_priv.h"
2425
#include "services/gatt/ble_svc_gatt.h"
2526
#include "../src/ble_gatt_priv.h"
2627

@@ -32,7 +33,7 @@ static uint16_t ble_svc_gatt_end_handle;
3233
#define BLE_SVC_GATT_SRV_SUP_FEAT_EATT_BIT (0x00)
3334

3435
/* Client supported features */
35-
#define BLE_SVC_GATT_CLI_SUP_FEAT_ROBUST_CATCHING_BIT (0x00)
36+
#define BLE_SVC_GATT_CLI_SUP_FEAT_ROBUST_CACHING_BIT (0x00)
3637
#define BLE_SVC_GATT_CLI_SUP_FEAT_EATT_BIT (0x01)
3738
#define BLE_SVC_GATT_CLI_SUP_FEAT_MULT_NTF_BIT (0x02)
3839

@@ -51,6 +52,10 @@ static int
5152
ble_svc_gatt_cl_sup_feat_access(uint16_t conn_handle, uint16_t attr_handle,
5253
struct ble_gatt_access_ctxt *ctxt, void *arg);
5354

55+
static int
56+
ble_svc_gatt_db_hash_access(uint16_t conn_handle, uint16_t attr_handle,
57+
struct ble_gatt_access_ctxt *ctxt, void *arg);
58+
5459
static const struct ble_gatt_svc_def ble_svc_gatt_defs[] = {
5560
{
5661
/*** Service: GATT */
@@ -73,6 +78,13 @@ static const struct ble_gatt_svc_def ble_svc_gatt_defs[] = {
7378
.access_cb = ble_svc_gatt_cl_sup_feat_access,
7479
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_WRITE,
7580
},
81+
#if MYNEWT_VAL(BLE_ATT_SVR_ROBUST_CACHE)
82+
{
83+
.uuid = BLE_UUID16_DECLARE(BLE_SVC_GATT_CHR_DATABASE_HASH_UUID16),
84+
.access_cb = ble_svc_gatt_db_hash_access,
85+
.flags = BLE_GATT_CHR_F_READ,
86+
},
87+
#endif
7688
{
7789
0, /* No more characteristics in this service. */
7890
}
@@ -121,6 +133,21 @@ ble_svc_gatt_cl_sup_feat_access(uint16_t conn_handle, uint16_t attr_handle,
121133
return 0;
122134
}
123135

136+
static int
137+
ble_svc_gatt_db_hash_access(uint16_t conn_handle, uint16_t attr_handle,
138+
struct ble_gatt_access_ctxt *ctxt, void *arg)
139+
{
140+
int rc;
141+
142+
if (ctxt->op != BLE_GATT_ACCESS_OP_READ_CHR) {
143+
return BLE_ATT_ERR_WRITE_NOT_PERMITTED;
144+
}
145+
146+
rc = os_mbuf_append(ctxt->om, db_hash, sizeof(db_hash));
147+
148+
return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
149+
}
150+
124151
static int
125152
ble_svc_gatt_access(uint16_t conn_handle, uint16_t attr_handle,
126153
struct ble_gatt_access_ctxt *ctxt, void *arg)
@@ -193,4 +220,8 @@ ble_svc_gatt_init(void)
193220
if (MYNEWT_VAL(BLE_ATT_SVR_NOTIFY_MULTI) > 0) {
194221
ble_svc_gatt_local_cl_sup_feat |= (1 << BLE_SVC_GATT_CLI_SUP_FEAT_MULT_NTF_BIT);
195222
}
223+
224+
if (MYNEWT_VAL(BLE_ATT_SVR_ROBUST_CACHE) > 0) {
225+
ble_svc_gatt_local_cl_sup_feat |= (1 << BLE_SVC_GATT_CLI_SUP_FEAT_ROBUST_CACHING_BIT);
226+
}
196227
}

nimble/host/src/ble_att_priv.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,9 @@ uint16_t ble_att_mtu_by_cid(uint16_t conn_handle, uint16_t cid);
173173
int ble_att_init(void);
174174

175175
/*** @svr */
176+
/** Type definition for ATT svr entry interation callback. */
177+
typedef int (*ble_gatts_entry_foreach)(struct ble_att_svr_entry *entry,
178+
void *arg);
176179

177180
int ble_att_svr_start(void);
178181

@@ -217,6 +220,8 @@ void ble_att_svr_prep_clear(struct ble_att_prep_entry_list *prep_list);
217220
int ble_att_svr_read_handle(uint16_t conn_handle, uint16_t attr_handle,
218221
uint16_t offset, struct os_mbuf *om,
219222
uint8_t *out_att_err);
223+
void ble_att_svr_foreach(uint16_t start_handle, uint16_t end_handle,
224+
ble_gatts_entry_foreach cb, void *arg);
220225
void ble_att_svr_reset(void);
221226
int ble_att_svr_init(void);
222227

nimble/host/src/ble_att_svr.c

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,26 @@ ble_att_svr_find_by_uuid(struct ble_att_svr_entry *prev, const ble_uuid_t *uuid,
209209
return NULL;
210210
}
211211

212+
void ble_att_svr_foreach(uint16_t start_handle, uint16_t end_handle,
213+
ble_gatts_entry_foreach cb, void *arg)
214+
{
215+
int rc;
216+
struct ble_att_svr_entry *entry;
217+
218+
for (entry = STAILQ_FIRST(&ble_att_svr_list);
219+
entry != NULL || entry->ha_handle_id == end_handle;
220+
entry = STAILQ_NEXT(entry, ha_next)) {
221+
222+
if (entry->ha_handle_id == start_handle) {
223+
rc = cb(entry, arg);
224+
if (rc != 0) {
225+
break;
226+
}
227+
}
228+
start_handle++;
229+
}
230+
}
231+
212232
static int
213233
ble_att_svr_pullup_req_base(struct os_mbuf **om, int base_len,
214234
uint8_t *out_att_err)

nimble/host/src/ble_gatt_priv.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@ void ble_gattc_rx_find_info_idata(uint16_t conn_handle, uint16_t cid,
145145
void ble_gattc_rx_find_info_complete(uint16_t conn_handle, uint16_t cid, int status);
146146
void ble_gattc_connection_txable(uint16_t conn_handle);
147147
void ble_gattc_connection_broken(uint16_t conn_handle);
148+
int ble_gatts_calculate_db_hash(uint8_t *hash);
148149
int32_t ble_gattc_timer(void);
149150

150151
int ble_gattc_any_jobs(void);

nimble/host/src/ble_gatts.c

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@
2525
#include "host/ble_uuid.h"
2626
#include "host/ble_store.h"
2727
#include "ble_hs_priv.h"
28+
#include "tinycrypt/aes.h"
29+
#include "tinycrypt/cmac_mode.h"
30+
#include "tinycrypt/constants.h"
2831

2932
#define BLE_GATTS_INCLUDE_SZ 6
3033
#define BLE_GATTS_CHR_MAX_SZ 19
@@ -65,6 +68,10 @@ struct ble_gatts_clt_cfg {
6568
static struct ble_gatts_clt_cfg *ble_gatts_clt_cfgs;
6669
static int ble_gatts_num_cfgable_chrs;
6770

71+
#if MYNEWT_VAL(BLE_ATT_SVR_ROBUST_CACHE)
72+
uint8_t db_hash[16];
73+
#endif
74+
6875
STATS_SECT_DECL(ble_gatts_stats) ble_gatts_stats;
6976
STATS_NAME_START(ble_gatts_stats)
7077
STATS_NAME(ble_gatts_stats, svcs)
@@ -1061,6 +1068,8 @@ ble_gatts_register_svcs(const struct ble_gatt_svc_def *svcs,
10611068
int rc;
10621069
int i;
10631070

1071+
num_svcs = 0;
1072+
10641073
for (i = 0; svcs[i].type != BLE_GATT_SVC_TYPE_END; i++) {
10651074
idx = ble_gatts_num_svc_entries + i;
10661075
if (idx >= ble_hs_max_services) {
@@ -1227,6 +1236,13 @@ ble_gatts_start(void)
12271236
}
12281237
ble_gatts_free_svc_defs();
12291238

1239+
#if MYNEWT_VAL(BLE_ATT_SVR_ROBUST_CACHE)
1240+
rc = ble_gatts_calculate_db_hash(db_hash);
1241+
if (rc != 0) {
1242+
goto done;
1243+
}
1244+
#endif
1245+
12301246
if (ble_gatts_num_cfgable_chrs == 0) {
12311247
rc = 0;
12321248
goto done;
@@ -2226,6 +2242,87 @@ ble_gatts_lcl_svc_foreach(ble_gatt_svc_foreach_fn cb, void *arg)
22262242
}
22272243
}
22282244

2245+
/* Helpers to append data to buf */
2246+
#define BUF_PUT_LE16(buf, buf_len, val) \
2247+
do { \
2248+
put_le16((buf) + (buf_len), (val)); \
2249+
(buf_len) += 2; \
2250+
} while (0)
2251+
2252+
int ble_gatt_foreach_hash_append(struct ble_att_svr_entry *entry, void *arg)
2253+
{
2254+
uint16_t uuid;
2255+
struct os_mbuf *om;
2256+
uint8_t buf[24];
2257+
uint16_t buf_len;
2258+
int rc;
2259+
2260+
uuid = ble_uuid_u16(entry->ha_uuid);
2261+
buf_len = 0;
2262+
switch (uuid) {
2263+
case BLE_ATT_UUID_PRIMARY_SERVICE:
2264+
case BLE_ATT_UUID_SECONDARY_SERVICE:
2265+
case BLE_ATT_UUID_INCLUDE:
2266+
case BLE_ATT_UUID_CHARACTERISTIC:
2267+
case BLE_GATT_DSC_EXT_PROP_UUID16:
2268+
/* attr handle */
2269+
BUF_PUT_LE16(buf, buf_len, entry->ha_handle_id);
2270+
/* attr type */
2271+
BUF_PUT_LE16(buf, buf_len, uuid);
2272+
rc = ble_att_svr_read_local(entry->ha_handle_id, &om);
2273+
if (rc != 0) {
2274+
return rc;
2275+
}
2276+
os_mbuf_copydata(om, 0, os_mbuf_len(om), buf + buf_len);
2277+
buf_len += os_mbuf_len(om);
2278+
break;
2279+
2280+
case BLE_GATT_DSC_CLT_CFG_UUID16:
2281+
BUF_PUT_LE16(buf, buf_len, entry->ha_handle_id);
2282+
BUF_PUT_LE16(buf, buf_len, uuid);
2283+
break;
2284+
default:
2285+
return 0;
2286+
}
2287+
if (tc_cmac_update(arg, buf, buf_len) == TC_CRYPTO_FAIL) {
2288+
return BLE_HS_EUNKNOWN;
2289+
}
2290+
2291+
return 0;
2292+
}
2293+
2294+
/**
2295+
* Calculate db_hash
2296+
* @param hash
2297+
* @return
2298+
*/
2299+
2300+
int ble_gatts_calculate_db_hash(uint8_t *hash)
2301+
{
2302+
#if !MYNEWT_VAL(BLE_ATT_SVR_ROBUST_CACHE)
2303+
return BLE_HS_ENOTSUP;
2304+
#endif
2305+
struct tc_aes_key_sched_struct sched;
2306+
struct tc_cmac_struct state;
2307+
2308+
/* k is the 128-bit key, which shall be all zero (7.3.1 Core spec) */
2309+
const uint8_t key[16] = {0};
2310+
2311+
if (tc_cmac_setup(&state, key, &sched) == TC_CRYPTO_FAIL) {
2312+
return BLE_HS_EUNKNOWN;
2313+
}
2314+
2315+
ble_att_svr_foreach(0x0001, 0xFFFF, ble_gatt_foreach_hash_append, &state);
2316+
2317+
if (tc_cmac_final(hash, &state) == TC_CRYPTO_FAIL) {
2318+
return BLE_HS_EUNKNOWN;
2319+
}
2320+
2321+
swap_in_place(hash, 16);
2322+
2323+
return 0;
2324+
}
2325+
22292326
int
22302327
ble_gatts_reset(void)
22312328
{

nimble/host/src/ble_hs_priv.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,8 @@ extern uint16_t ble_hs_max_attrs;
100100
extern uint16_t ble_hs_max_services;
101101
extern uint16_t ble_hs_max_client_configs;
102102

103+
extern uint8_t db_hash[16];
104+
103105
void ble_hs_process_rx_data_queue(void);
104106
int ble_hs_tx_data(struct os_mbuf *om);
105107
void ble_hs_wakeup_tx(void);

0 commit comments

Comments
 (0)