feature : Gatt Caching

This commit is contained in:
Roshan Bangar
2023-10-30 14:32:03 +05:30
committed by Abhinav Kudnar
parent 69cc84e161
commit a6c1180ea2
19 changed files with 3777 additions and 9 deletions
+9
View File
@@ -109,6 +109,8 @@ struct os_mbuf;
/**Insufficient Resources to complete the request. */
#define BLE_ATT_ERR_INSUFFICIENT_RES 0x11
#define BLE_ATT_ERR_DB_OUT_OF_SYNC 0x12
#define BLE_ATT_ERR_VALUE_NOT_ALLOWED 0x13
/** @} */
@@ -186,6 +188,13 @@ struct os_mbuf;
/** Execute Write Response. */
#define BLE_ATT_OP_EXEC_WRITE_RSP 0x19
/** Read Multiple Variable Lenght Request */
#define BLE_ATT_OP_READ_MULT_VAR_REQ 0x20
/** Read Multiple Variable Lenght Response */
#define BLE_ATT_OP_READ_MULT_VAR_RSP 0x21
/** Notify Request. */
#define BLE_ATT_OP_NOTIFY_REQ 0x1b
+42
View File
@@ -1101,6 +1101,48 @@ int ble_gatts_reset(void);
*/
int ble_gatts_start(void);
/**
* Saves Client Supported Features for specified connection.
*
* @param conn_handle Connection handle identifying connection for
* which Client Supported Features should be saved
* @param om The mbuf chain to set value from.
*
* @return 0 on success;
* BLE_HS_ENOTCONN if no matching connection
* was found
* BLE_HS_EINVAL if supplied buffer is empty or
* if any Client Supported Feature was
* attempted to be disabled.
* A BLE host core return code on unexpected
* error.
*
*/
int ble_gatts_peer_cl_sup_feat_update(uint16_t conn_handle,
struct os_mbuf *om);
/**
* Gets Client Supported Features for specified connection.
*
* @param conn_handle Connection handle identifying connection for
* which Client Supported Features should be saved
* @param out_supported_feat Client supported features to be returned.
*
* @return 0 on success;
* BLE_HS_ENOTCONN if no matching connection
* was found
* BLE_HS_EINVAL if supplied buffer is empty or
* if any Client Supported Feature was
* attempted to be disabled.
* A BLE host core return code on unexpected
* error.
*
*/
int ble_gatts_peer_cl_sup_feat_get(uint16_t conn_handle, uint8_t *out_supported_feat, uint8_t len);
#if MYNEWT_VAL(BLE_GATT_CACHING)
int ble_gatts_calculate_hash(uint8_t *out_hash_key);
#endif
#ifdef __cplusplus
}
#endif
@@ -21,6 +21,7 @@
#define H_BLE_SVC_GATT_
#include <inttypes.h>
#include "syscfg/syscfg.h"
#ifdef __cplusplus
extern "C" {
@@ -29,7 +30,19 @@ extern "C" {
struct ble_hs_cfg;
#define BLE_SVC_GATT_CHR_SERVICE_CHANGED_UUID16 0x2a05
#define BLE_SVC_GATT_CHR_SERVER_SUPPORTED_FEAT_UUID16 0x2b3a
#define BLE_SVC_GATT_CHR_CLIENT_SUPPORTED_FEAT_UUID16 0x2b29
#if MYNEWT_VAL(BLE_GATT_CACHING)
#define BLE_SVC_GATT_CHR_DATABASE_HASH_UUID16 0x2b2a
uint16_t ble_svc_gatt_changed_handle();
uint16_t ble_svc_gatt_hash_handle();
uint16_t ble_svc_gatt_csf_handle();
uint8_t ble_svc_gatt_get_csfs();
#endif
uint8_t ble_svc_gatt_get_local_cl_supported_feat(void);
void ble_svc_gatt_changed(uint16_t start_handle, uint16_t end_handle);
void ble_svc_gatt_init(void);
+129 -2
View File
@@ -23,14 +23,38 @@
#include "host/ble_hs.h"
#include "services/gatt/ble_svc_gatt.h"
#if MYNEWT_VAL(BLE_GATT_CACHING)
static uint16_t ble_svc_gatt_db_hash_handle;
static uint16_t ble_svc_gatt_client_supp_feature_handle;
#endif
static uint16_t ble_svc_gatt_changed_val_handle;
static uint16_t ble_svc_gatt_start_handle;
static uint16_t ble_svc_gatt_end_handle;
/* Server supported features */
#define BLE_SVC_GATT_SRV_SUP_FEAT_EATT_BIT (0x00)
/* Client supported features */
#define BLE_SVC_GATT_CLI_SUP_FEAT_ROBUST_CATCHING_BIT (0x00)
#define BLE_SVC_GATT_CLI_SUP_FEAT_EATT_BIT (0x01)
#define BLE_SVC_GATT_CLI_SUP_FEAT_MULT_NTF_BIT (0x02)
static uint8_t ble_svc_gatt_local_srv_sup_feat = 0;
static uint8_t ble_svc_gatt_local_cl_sup_feat = 0;
static int
ble_svc_gatt_access(uint16_t conn_handle, uint16_t attr_handle,
struct ble_gatt_access_ctxt *ctxt, void *arg);
static int
ble_svc_gatt_srv_sup_feat_access(uint16_t conn_handle, uint16_t attr_handle,
struct ble_gatt_access_ctxt *ctxt, void *arg);
static int
ble_svc_gatt_cl_sup_feat_access(uint16_t conn_handle, uint16_t attr_handle,
struct ble_gatt_access_ctxt *ctxt, void *arg);
static const struct ble_gatt_svc_def ble_svc_gatt_defs[] = {
{
/*** Service: GATT */
@@ -41,7 +65,29 @@ static const struct ble_gatt_svc_def ble_svc_gatt_defs[] = {
.access_cb = ble_svc_gatt_access,
.val_handle = &ble_svc_gatt_changed_val_handle,
.flags = BLE_GATT_CHR_F_INDICATE,
}, {
},
{
.uuid = BLE_UUID16_DECLARE(BLE_SVC_GATT_CHR_SERVER_SUPPORTED_FEAT_UUID16),
.access_cb = ble_svc_gatt_srv_sup_feat_access,
.flags = BLE_GATT_CHR_F_READ,
},
{
.uuid = BLE_UUID16_DECLARE(BLE_SVC_GATT_CHR_CLIENT_SUPPORTED_FEAT_UUID16),
.access_cb = ble_svc_gatt_cl_sup_feat_access,
#if MYNEWT_VAL(BLE_GATT_CACHING)
.val_handle = &ble_svc_gatt_client_supp_feature_handle,
#endif
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_WRITE,
},
#if MYNEWT_VAL(BLE_GATT_CACHING)
{
.uuid = BLE_UUID16_DECLARE(BLE_SVC_GATT_CHR_DATABASE_HASH_UUID16),
.access_cb = ble_svc_gatt_access,
.val_handle = &ble_svc_gatt_db_hash_handle,
.flags = BLE_GATT_CHR_F_READ,
},
#endif
{
0, /* No more characteristics in this service. */
} },
},
@@ -51,6 +97,41 @@ static const struct ble_gatt_svc_def ble_svc_gatt_defs[] = {
},
};
static int
ble_svc_gatt_srv_sup_feat_access(uint16_t conn_handle, uint16_t attr_handle,
struct ble_gatt_access_ctxt *ctxt, void *arg)
{
if (ctxt->op != BLE_GATT_ACCESS_OP_READ_CHR) {
return BLE_ATT_ERR_WRITE_NOT_PERMITTED;
}
os_mbuf_append(ctxt->om, &ble_svc_gatt_local_srv_sup_feat, sizeof(ble_svc_gatt_local_srv_sup_feat));
return 0;
}
static int
ble_svc_gatt_cl_sup_feat_access(uint16_t conn_handle, uint16_t attr_handle,
struct ble_gatt_access_ctxt *ctxt, void *arg)
{
uint8_t supported_feat;
int rc;
if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR) {
rc = ble_gatts_peer_cl_sup_feat_get(conn_handle, &supported_feat, 1);
if (rc != 0) {
return BLE_ATT_ERR_UNLIKELY;
}
os_mbuf_append(ctxt->om, &supported_feat, sizeof(supported_feat));
return 0;
}
if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) {
return ble_gatts_peer_cl_sup_feat_update(conn_handle, ctxt->om);
}
return 0;
}
static int
ble_svc_gatt_access(uint16_t conn_handle, uint16_t attr_handle,
struct ble_gatt_access_ctxt *ctxt, void *arg)
@@ -63,20 +144,53 @@ ble_svc_gatt_access(uint16_t conn_handle, uint16_t attr_handle,
* Therefore, this callback should only get called during an attempt to
* read the characteristic.
*/
#if !MYNEWT_VAL(BLE_GATT_CACHING)
assert(ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR);
assert(ctxt->chr == &ble_svc_gatt_defs[0].characteristics[0]);
u8p = os_mbuf_extend(ctxt->om, 4);
if (u8p == NULL) {
return BLE_HS_ENOMEM;
}
assert(ctxt->chr == &ble_svc_gatt_defs[0].characteristics[0]);
put_le16(u8p + 0, ble_svc_gatt_start_handle);
put_le16(u8p + 2, ble_svc_gatt_end_handle);
#else
int rc;
if(ctxt->chr == &ble_svc_gatt_defs[0].characteristics[0]){
u8p = os_mbuf_extend(ctxt->om, 4);
if (u8p == NULL) {
return BLE_HS_ENOMEM;
}
put_le16(u8p + 0, ble_svc_gatt_start_handle);
put_le16(u8p + 2, ble_svc_gatt_end_handle);
}
if (attr_handle == ble_svc_gatt_db_hash_handle) {
assert(ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR);
uint8_t database_hash[16] = {0};
rc = ble_gatts_calculate_hash(database_hash);
if(rc != 0) {
return BLE_ATT_ERR_UNLIKELY;
}
rc = os_mbuf_append(ctxt->om, database_hash, sizeof(database_hash));
if(rc != 0) {
return BLE_ATT_ERR_UNLIKELY;
}
}
#endif
return 0;
}
uint8_t
ble_svc_gatt_get_local_cl_supported_feat(void)
{
return ble_svc_gatt_local_cl_sup_feat;
}
/**
* Indicates a change in attribute assignment to all subscribed peers.
* Unconnected bonded peers receive an indication when they next connect.
@@ -92,6 +206,19 @@ ble_svc_gatt_changed(uint16_t start_handle, uint16_t end_handle)
ble_gatts_chr_updated(ble_svc_gatt_changed_val_handle);
}
#if MYNEWT_VAL(BLE_GATT_CACHING)
uint16_t ble_svc_gatt_changed_handle() {
return ble_svc_gatt_changed_val_handle;
}
uint16_t ble_svc_gatt_hash_handle() {
return ble_svc_gatt_db_hash_handle;
}
uint16_t ble_svc_gatt_csf_handle() {
return ble_svc_gatt_client_supp_feature_handle;
}
#endif
void
ble_svc_gatt_init(void)
{
+1
View File
@@ -69,6 +69,7 @@ static const struct ble_att_rx_dispatch_entry ble_att_rx_dispatch[] = {
{ BLE_ATT_OP_NOTIFY_REQ, ble_att_svr_rx_notify },
{ BLE_ATT_OP_INDICATE_REQ, ble_att_svr_rx_indicate },
{ BLE_ATT_OP_INDICATE_RSP, ble_att_clt_rx_indicate },
{ BLE_ATT_OP_READ_MULT_VAR_REQ, ble_att_svr_rx_read_mult_var },
{ BLE_ATT_OP_WRITE_CMD, ble_att_svr_rx_write_no_rsp },
};
+7
View File
@@ -149,6 +149,11 @@ int ble_att_svr_register(const ble_uuid_t *uuid, uint8_t flags,
#if MYNEWT_VAL(BLE_DYNAMIC_SERVICE)
int ble_att_svr_deregister(uint16_t start_handle, uint16_t end_group_handle);
#endif
#if MYNEWT_VAL(BLE_GATT_CACHING)
int ble_att_get_database_size(int *out_size);
int ble_att_fill_database_info(uint8_t *out_data);
#endif
struct ble_att_svr_entry {
STAILQ_ENTRY(ble_att_svr_entry) ha_next;
@@ -200,6 +205,8 @@ int ble_att_svr_rx_read(uint16_t conn_handle,
struct os_mbuf **rxom);
int ble_att_svr_rx_read_blob(uint16_t conn_handle,
struct os_mbuf **rxom);
int ble_att_svr_rx_read_mult_var(uint16_t conn_handle,
struct os_mbuf **rxom);
int ble_att_svr_rx_read_mult(uint16_t conn_handle,
struct os_mbuf **rxom);
int ble_att_svr_rx_write(uint16_t conn_handle,
+426
View File
@@ -1308,6 +1308,37 @@ done:
return rc;
}
#if MYNEWT_VAL(BLE_GATT_CACHING)
static void ble_att_svr_make_conn_aware(uint16_t conn_handle) {
struct ble_hs_conn *conn;
struct ble_hs_conn_addrs addrs;
int i = 0;
conn = ble_hs_conn_find_assert(conn_handle);
conn->bhc_gatt_svr.aware_state = true;
ble_hs_conn_addrs(conn, &addrs);
for(i = 0; i < MYNEWT_VAL(BLE_STORE_MAX_BONDS); i++) {
if(memcmp(ble_gatts_conn_aware_states[i].peer_id_addr,
addrs.peer_id_addr.val, sizeof addrs.peer_id_addr.val)) {
ble_gatts_conn_aware_states[i].aware = true;
}
}
}
static bool ble_att_svr_check_conn_aware(uint16_t conn_handle) {
struct ble_hs_conn *conn;
conn = ble_hs_conn_find_assert(conn_handle);
return conn->bhc_gatt_svr.aware_state;
}
static uint8_t * ble_att_svr_get_csfs(uint16_t conn_handle) {
struct ble_hs_conn *conn;
conn = ble_hs_conn_find_assert(conn_handle);
return conn->bhc_gatt_svr.peer_cl_sup_feat;
}
#endif
static int
ble_att_svr_build_read_type_rsp(uint16_t conn_handle,
uint16_t start_handle, uint16_t end_handle,
@@ -1476,6 +1507,15 @@ ble_att_svr_rx_read_type(uint16_t conn_handle, struct os_mbuf **rxom)
goto done;
}
#if MYNEWT_VAL(BLE_GATT_CACHING)
ble_hs_lock();
ble_att_svr_make_conn_aware(conn_handle);
ble_hs_unlock();
if(rc != 0) {
goto done;
}
#endif
rc = ble_att_svr_build_read_type_rsp(conn_handle, start_handle, end_handle,
&uuid.u, rxom, &txom, &att_err,
&err_handle);
@@ -1518,6 +1558,20 @@ ble_att_svr_rx_read(uint16_t conn_handle, struct os_mbuf **rxom)
err_handle = le16toh(req->barq_handle);
#if MYNEWT_VAL(BLE_GATT_CACHING)
ble_hs_lock();
if((ble_att_svr_get_csfs(conn_handle)[0] & 1)
&& ble_svc_gatt_csf_handle() != err_handle ) {
if (!ble_att_svr_check_conn_aware(conn_handle)) {
att_err = BLE_ATT_ERR_DB_OUT_OF_SYNC;
rc = BLE_HS_EREJECT;
ble_att_svr_make_conn_aware(conn_handle);
ble_hs_unlock();
goto done;
}
}
ble_hs_unlock();
#endif
/* Just reuse the request buffer for the response. */
txom = *rxom;
*rxom = NULL;
@@ -1568,6 +1622,21 @@ ble_att_svr_rx_read_blob(uint16_t conn_handle, struct os_mbuf **rxom)
err_handle = le16toh(req->babq_handle);
offset = le16toh(req->babq_offset);
#if MYNEWT_VAL(BLE_GATT_CACHING)
ble_hs_lock();
if((ble_att_svr_get_csfs(conn_handle)[0] & 1)
&& ble_svc_gatt_csf_handle() != err_handle ) {
if (!ble_att_svr_check_conn_aware(conn_handle)) {
att_err = BLE_ATT_ERR_DB_OUT_OF_SYNC;
rc = BLE_HS_EREJECT;
ble_att_svr_make_conn_aware(conn_handle);
ble_hs_unlock();
goto done;
}
}
ble_hs_unlock();
#endif
/* Just reuse the request buffer for the response. */
txom = *rxom;
*rxom = NULL;
@@ -1671,13 +1740,156 @@ ble_att_svr_rx_read_mult(uint16_t conn_handle, struct os_mbuf **rxom)
err_handle = 0;
att_err = 0;
#if MYNEWT_VAL(BLE_GATT_CACHING)
ble_hs_lock();
if((ble_att_svr_get_csfs(conn_handle)[0] & 1)
&& ble_svc_gatt_csf_handle() != err_handle ) {
if (!ble_att_svr_check_conn_aware(conn_handle)) {
att_err = BLE_ATT_ERR_DB_OUT_OF_SYNC;
rc = BLE_HS_EREJECT;
ble_att_svr_make_conn_aware(conn_handle);
ble_hs_unlock();
goto done;
}
}
ble_hs_unlock();
#endif
rc = ble_att_svr_build_read_mult_rsp(conn_handle, rxom, &txom, &att_err,
&err_handle);
#if MYNEWT_VAL(BLE_GATT_CACHING)
done :
#endif
return ble_att_svr_tx_rsp(conn_handle, rc, txom, BLE_ATT_OP_READ_MULT_REQ,
att_err, err_handle);
}
static int
ble_att_svr_build_read_mult_rsp_var(uint16_t conn_handle,
struct os_mbuf **rxom,
struct os_mbuf **out_txom,
uint8_t *att_err,
uint16_t *err_handle)
{
struct os_mbuf *txom;
uint16_t handle;
uint16_t mtu;
uint16_t tuple_len;
struct os_mbuf *tmp = NULL;
int rc;
mtu = ble_att_mtu(conn_handle);
rc = ble_att_svr_pkt(rxom, &txom, att_err);
if (rc != 0) {
*err_handle = 0;
goto done;
}
if (ble_att_cmd_prepare(BLE_ATT_OP_READ_MULT_VAR_RSP, 0, txom) == NULL) {
*att_err = BLE_ATT_ERR_INSUFFICIENT_RES;
*err_handle = 0;
rc = BLE_HS_ENOMEM;
goto done;
}
tmp = os_msys_get_pkthdr(2, 0);
/* Iterate through requested handles, reading the corresponding attribute
* for each. Stop when there are no more handles to process, or the
* response is full.
*/
while (OS_MBUF_PKTLEN(*rxom) >= 2 && OS_MBUF_PKTLEN(txom) < mtu) {
/* Ensure the full 16-bit handle is contiguous at the start of the
* mbuf.
*/
rc = ble_att_svr_pullup_req_base(rxom, 2, att_err);
if (rc != 0) {
*err_handle = 0;
goto done;
}
/* Extract the 16-bit handle and strip it from the front of the
* mbuf.
*/
handle = get_le16((*rxom)->om_data);
os_mbuf_adj(*rxom, 2);
rc = ble_att_svr_read_handle(conn_handle, handle, 0, tmp, att_err);
if (rc != 0) {
*err_handle = handle;
goto done;
}
tuple_len = OS_MBUF_PKTLEN(tmp);
rc = os_mbuf_append(txom, &tuple_len, sizeof(tuple_len));
if (rc != 0) {
*err_handle = handle;
goto done;
}
if (tuple_len != 0) {
rc = os_mbuf_appendfrom(txom, tmp, 0, tuple_len);
if (rc != 0) {
*err_handle = handle;
goto done;
}
os_mbuf_adj(tmp, tuple_len);
}
}
rc = 0;
done:
if (tmp) {
os_mbuf_free_chain(tmp);
}
*out_txom = txom;
return rc;
}
int
ble_att_svr_rx_read_mult_var(uint16_t conn_handle, struct os_mbuf **rxom)
{
#if (!MYNEWT_VAL(BLE_ATT_SVR_READ_MULT) || (MYNEWT_VAL(BLE_VERSION) < 52))
return BLE_HS_ENOTSUP;
#endif
struct os_mbuf *txom;
uint16_t err_handle;
uint8_t att_err;
int rc;
/* Initialize some values in case of early error. */
txom = NULL;
err_handle = 0;
att_err = 0;
#if MYNEWT_VAL(BLE_GATT_CACHING)
ble_hs_lock();
if((ble_att_svr_get_csfs(conn_handle)[0] & 1)
&& ble_svc_gatt_csf_handle() != err_handle ) {
if (!ble_att_svr_check_conn_aware(conn_handle)) {
att_err = BLE_ATT_ERR_DB_OUT_OF_SYNC;
rc = BLE_HS_EREJECT;
ble_att_svr_make_conn_aware(conn_handle);
ble_hs_unlock();
goto done;
}
}
ble_hs_unlock();
#endif
rc = ble_att_svr_build_read_mult_rsp_var(conn_handle, rxom, &txom, &att_err,
&err_handle);
#if MYNEWT_VAL(BLE_GATT_CACHING)
done:
#endif
return ble_att_svr_tx_rsp(conn_handle, rc, txom,
BLE_ATT_OP_READ_MULT_VAR_REQ,
att_err, err_handle);
}
static int
ble_att_svr_is_valid_read_group_type(const ble_uuid_t *uuid)
{
@@ -1958,6 +2170,15 @@ ble_att_svr_rx_read_group_type(uint16_t conn_handle, struct os_mbuf **rxom)
goto done;
}
#if MYNEWT_VAL(BLE_GATT_CACHING)
ble_hs_lock();
ble_att_svr_make_conn_aware(conn_handle);
ble_hs_unlock();
if(rc != 0) {
goto done;
}
#endif
om_uuid_len = OS_MBUF_PKTHDR(*rxom)->omp_len - sizeof(*req);
rc = ble_uuid_init_from_att_mbuf(&uuid, *rxom, sizeof(*req), om_uuid_len);
if (rc != 0) {
@@ -2046,6 +2267,21 @@ ble_att_svr_rx_write(uint16_t conn_handle, struct os_mbuf **rxom)
handle = le16toh(req->bawq_handle);
#if MYNEWT_VAL(BLE_GATT_CACHING)
ble_hs_lock();
if((ble_att_svr_get_csfs(conn_handle)[0] & 1)
&& ble_svc_gatt_csf_handle() != handle) {
if (!ble_att_svr_check_conn_aware(conn_handle)) {
att_err = BLE_ATT_ERR_DB_OUT_OF_SYNC;
rc = BLE_HS_EREJECT;
ble_att_svr_make_conn_aware(conn_handle);
ble_hs_unlock();
goto done;
}
}
ble_hs_unlock();
#endif
/* Allocate the write response. This must be done prior to processing the
* request. See the note at the top of this file for details.
*/
@@ -2077,6 +2313,16 @@ ble_att_svr_rx_write_no_rsp(uint16_t conn_handle, struct os_mbuf **rxom)
return BLE_HS_ENOTSUP;
#endif
#if MYNEWT_VAL(BLE_GATT_CACHING)
ble_hs_lock();
if ((ble_att_svr_get_csfs(conn_handle)[0] & 1) &&
!ble_att_svr_check_conn_aware(conn_handle)) {
ble_hs_unlock();
return BLE_HS_EREJECT;
}
ble_hs_unlock();
#endif
struct ble_att_write_req *req;
uint8_t att_err;
uint16_t handle;
@@ -2388,6 +2634,21 @@ ble_att_svr_rx_prep_write(uint16_t conn_handle, struct os_mbuf **rxom)
err_handle = le16toh(req->bapc_handle);
#if MYNEWT_VAL(BLE_GATT_CACHING)
ble_hs_lock();
if((ble_att_svr_get_csfs(conn_handle)[0] & 1)
&& ble_svc_gatt_csf_handle() != err_handle ) {
if (!ble_att_svr_check_conn_aware(conn_handle)) {
att_err = BLE_ATT_ERR_DB_OUT_OF_SYNC;
rc = BLE_HS_EREJECT;
ble_att_svr_make_conn_aware(conn_handle);
ble_hs_unlock();
goto done;
}
}
ble_hs_unlock();
#endif
attr_entry = ble_att_svr_find_by_handle(le16toh(req->bapc_handle));
/* A prepare write request gets rejected for the following reasons:
@@ -2461,6 +2722,21 @@ ble_att_svr_rx_exec_write(uint16_t conn_handle, struct os_mbuf **rxom)
txom = NULL;
err_handle = 0;
#if MYNEWT_VAL(BLE_GATT_CACHING)
ble_hs_lock();
if((ble_att_svr_get_csfs(conn_handle)[0] & 1)
&& ble_svc_gatt_csf_handle() != err_handle ) {
if (!ble_att_svr_check_conn_aware(conn_handle)) {
att_err = BLE_ATT_ERR_DB_OUT_OF_SYNC;
rc = BLE_HS_EREJECT;
ble_att_svr_make_conn_aware(conn_handle);
ble_hs_unlock();
goto done;
}
}
ble_hs_unlock();
#endif
rc = ble_att_svr_pullup_req_base(rxom, sizeof(*req), &att_err);
if (rc != 0) {
flags = 0;
@@ -2820,4 +3096,154 @@ ble_att_svr_init(void)
return 0;
}
/* Defined in Core spec v5.4 VOL 3 Part G 7.3.1 */
#if MYNEWT_VAL(BLE_GATT_CACHING)
int ble_att_get_database_size(int *out_size)
{
struct ble_att_svr_entry *entry;
ble_uuid16_t *uuid;
ble_uuid_any_t service_uuid;
uint8_t att_error;
int size = 0;
int rc;
for (entry = STAILQ_FIRST(&ble_att_svr_list);
entry != NULL;
entry = STAILQ_NEXT(entry, ha_next)) {
uuid = (ble_uuid16_t*)entry->ha_uuid;
if(uuid->value == BLE_ATT_UUID_PRIMARY_SERVICE ||
uuid->value == BLE_ATT_UUID_SECONDARY_SERVICE) {
rc = ble_att_svr_service_uuid(entry, &service_uuid, &att_error);
if(rc != 0) {
return rc;
}
/* handle (2 bytes) + type(2 bytes) + uuid (variable) */
size += (4 + ble_uuid_length(&service_uuid.u));
}
else if(uuid->value == BLE_ATT_UUID_INCLUDE) {
rc = ble_att_svr_service_uuid(entry, &service_uuid, &att_error);
if(rc != 0) {
return rc;
}
/* handle + type + inc_svc_att_handle + end_grp_handle + uuid */
size += (8 + ble_uuid_length(&service_uuid.u));
}
else if(uuid->value == BLE_ATT_UUID_CHARACTERISTIC) {
/* uuid is stored in the value attribute */
entry = STAILQ_NEXT(entry, ha_next);
/* handle(2 bytes) + type(2 bytes) + properties(1 byte)
+ val_handle(2 bytes) + uuid */
size += (7 + ble_uuid_length(entry->ha_uuid));
}
else if(uuid->value == 0x2901 ||
uuid->value == 0x2902 ||
uuid->value == 0x2903 ||
uuid->value == 0x2904 ||
uuid->value == 0x2905) {
/* handle + type */
size += 4;
}
else if(uuid->value == 0x2901) {
/* handle + type + value(2 bytes) */
size += 6;
}
}
*out_size = size;
return 0;
}
int ble_att_fill_database_info(uint8_t *out_data)
{
struct ble_att_svr_entry *entry;
ble_uuid16_t *uuid;
ble_uuid_any_t service_uuid;
uint8_t att_error;
uint8_t *data;
uint8_t val[20];
uint16_t attr_len;
int rc;
data = out_data;
for (entry = STAILQ_FIRST(&ble_att_svr_list);
entry != NULL;
entry = STAILQ_NEXT(entry, ha_next)) {
uuid = BLE_UUID16(entry->ha_uuid);
if(uuid->value == BLE_ATT_UUID_PRIMARY_SERVICE ||
uuid->value == BLE_ATT_UUID_SECONDARY_SERVICE) {
rc = ble_att_svr_service_uuid(entry, &service_uuid, &att_error);
if(rc != 0) {
return rc;
}
/* handle (2 bytes) + type(2 bytes) + uuid (variable) */
put_le16(data, entry->ha_handle_id);
uuid = BLE_UUID16(entry->ha_uuid);
put_le16(data + 2, uuid->value);
ble_uuid_flat(&service_uuid.u, data + 4);
data += (4 + ble_uuid_length(&service_uuid.u));
}
else if(uuid->value == BLE_ATT_UUID_INCLUDE) {
rc = ble_att_svr_read_flat(BLE_HS_CONN_HANDLE_NONE,
entry, 0, sizeof(val), val,
&attr_len, &att_error);
if(rc != 0) {
return rc;
}
/* handle + type + inc_svc_att_handle + end_grp_handle + uuid */
put_le16(data, entry->ha_handle_id);
uuid = BLE_UUID16(entry->ha_uuid);
put_le16(data + 2, uuid->value);
/* the data is already in LE format */
memcpy(data + 4, val, attr_len);
data += (4 + attr_len);
}
else if(uuid->value == BLE_ATT_UUID_CHARACTERISTIC) {
/* handle(2 bytes) + type(2 bytes) + properties(1 byte)
+ val_handle(2 bytes) + uuid */
put_le16(data, entry->ha_handle_id);
uuid = BLE_UUID16(entry->ha_uuid);
put_le16(data + 2, uuid->value);
rc = ble_att_svr_read_flat(BLE_HS_CONN_HANDLE_NONE,
entry, 0, sizeof(val), val,
&attr_len, &att_error);
if(rc != 0) {
return rc;
}
memcpy(data + 4, val, attr_len);
data += (4 + attr_len);
}
else if(uuid->value == 0x2901 ||
uuid->value == 0x2902 ||
uuid->value == 0x2903 ||
uuid->value == 0x2904 ||
uuid->value == 0x2905) {
/* handle + type */
put_le16(data, entry->ha_handle_id);
uuid = BLE_UUID16(entry->ha_uuid);
put_le16(data + 2, uuid->value);
data += 4;
}
else if(uuid->value == 0x2900) {
/* handle + type + value(2 bytes) */
put_le16(data, entry->ha_handle_id);
uuid = BLE_UUID16(entry->ha_uuid);
put_le16(data + 2, uuid->value);
rc = ble_att_svr_read_flat(BLE_HS_CONN_HANDLE_NONE,
entry, 0, sizeof(val), val,
&attr_len, &att_error);
if(rc != 0) {
return rc;
}
memcpy(data + 4, val, attr_len);
data += (4 + attr_len);
}
}
return 0;
}
#endif
#endif
+31
View File
@@ -27,6 +27,9 @@
#include "ble_hs_priv.h"
#include "ble_gap_priv.h"
#include "ble_hs_resolv_priv.h"
#if MYNEWT_VAL(BLE_GATT_CACHING)
#include "ble_gattc_cache_priv.h"
#endif
#ifndef min
#define min(a, b) ((a) < (b) ? (a) : (b))
@@ -1378,6 +1381,9 @@ ble_gap_conn_broken(uint16_t conn_handle, int reason)
ble_sm_connection_broken(conn_handle);
ble_gatts_connection_broken(conn_handle);
ble_gattc_connection_broken(conn_handle);
#if MYNEWT_VAL(BLE_GATT_CACHING)
ble_gattc_cache_conn_broken(conn_handle);
#endif
ble_hs_flow_connection_broken(conn_handle);;
ble_hs_atomic_conn_delete(conn_handle);
@@ -2094,6 +2100,9 @@ ble_gap_rx_conn_complete(struct ble_gap_conn_complete *evt, uint8_t instance)
struct ble_gap_event event;
struct ble_hs_conn *conn;
int rc;
#if MYNEWT_VAL(BLE_GATT_CACHING)
struct ble_hs_conn_addrs addrs
#endif
STATS_INC(ble_gap_stats, rx_conn_complete);
@@ -2216,6 +2225,13 @@ ble_gap_rx_conn_complete(struct ble_gap_conn_complete *evt, uint8_t instance)
event.connect.conn_handle = evt->connection_handle;
event.connect.status = 0;
/* add gatt connection */
#if MYNEWT_VAL(BLE_GATT_CACHING)
if (evt->role == BLE_HCI_LE_CONN_COMPLETE_ROLE_MASTER) {
ble_hs_conn_addrs(conn, &addrs);
rc = ble_gattc_cache_conn_create(conn->bhc_handle, addrs.peer_id_addr);
}
#endif
ble_gap_event_listener_call(&event);
ble_gap_call_conn_event_cb(&event, evt->connection_handle);
@@ -6859,6 +6875,9 @@ ble_gap_enc_event(uint16_t conn_handle, int status,
*/
if (security_restored) {
ble_gatts_bonding_restored(conn_handle);
#if MYNEWT_VAL(BLE_GATT_CACHING)
ble_gattc_cache_conn_bonding_restored(conn_handle);
#endif
return;
}
@@ -6868,6 +6887,9 @@ ble_gap_enc_event(uint16_t conn_handle, int status,
*/
if (bonded) {
ble_gatts_bonding_established(conn_handle);
#if MYNEWT_VAL(BLE_GATT_CACHING)
ble_gattc_cache_conn_bonding_established(conn_handle);
#endif
}
#endif
}
@@ -6947,7 +6969,16 @@ ble_gap_notify_rx_event(uint16_t conn_handle, uint16_t attr_handle,
#if (MYNEWT_VAL(BLE_GATT_NOTIFY) || MYNEWT_VAL(BLE_GATT_INDICATE)) && NIMBLE_BLE_CONNECT
struct ble_gap_event event;
#if MYNEWT_VAL(BLE_GATT_CACHING)
uint16_t start_handle;
uint16_t end_handle;
if (attr_handle == ble_gattc_cache_conn_get_svc_changed_handle(conn_handle)) {
start_handle = get_le16(om->om_data);
end_handle = get_le16(om->om_data + 2);
ble_gattc_cache_conn_update(conn_handle, start_handle, end_handle);
}
#endif
memset(&event, 0, sizeof event);
event.type = BLE_GAP_EVENT_NOTIFY_RX;
event.notify_rx.conn_handle = conn_handle;
+24
View File
@@ -88,6 +88,7 @@ extern STATS_SECT_DECL(ble_gatts_stats) ble_gatts_stats;
#define BLE_GATT_CHR_DECL_SZ_16 5
#define BLE_GATT_CHR_DECL_SZ_128 19
#define BLE_GATT_CHR_CLI_SUP_FEAT_SZ 1
typedef uint8_t ble_gatts_conn_flags;
@@ -98,8 +99,20 @@ struct ble_gatts_conn {
struct ble_gatts_clt_cfg *clt_cfgs;
#endif
int num_clt_cfgs;
#if MYNEWT_VAL(BLE_GATT_CACHING)
bool aware_state;
bool sent_err;
#endif
uint16_t indicate_val_handle;
/**
* For now only 3 bits in one octet are defined, but specification expects
* this service to be variable length with no upper bound. Let's make this
* future proof if more octets might be used.
* (Vol. 3, Part G, 7.2)
*/
uint8_t peer_cl_sup_feat[BLE_GATT_CHR_CLI_SUP_FEAT_SZ];
};
/*** @client. */
@@ -191,10 +204,21 @@ int ble_gatts_clt_cfg_access(uint16_t conn_handle, uint16_t attr_handle,
uint8_t op, uint16_t offset, struct os_mbuf **om,
void *arg);
#if MYNEWT_VAL(BLE_GATT_CACHING)
struct ble_gatts_aware_state {
uint8_t peer_id_addr[6];
bool aware;
};
extern struct ble_gatts_aware_state ble_gatts_conn_aware_states[MYNEWT_VAL(BLE_STORE_MAX_BONDS)];
#endif
/*** @misc. */
int ble_gatts_conn_can_alloc(void);
int ble_gatts_conn_init(struct ble_gatts_conn *gatts_conn);
int ble_gatts_init(void);
#if MYNEWT_VAL(BLE_GATT_CACHING)
int ble_gattc_cache_conn_init();
#endif
#ifdef __cplusplus
}
+107
View File
@@ -60,6 +60,7 @@
#include "host/ble_uuid.h"
#include "host/ble_gap.h"
#include "ble_hs_priv.h"
#include "ble_gattc_cache_priv.h"
#if NIMBLE_BLE_CONNECT
@@ -1535,6 +1536,13 @@ ble_gattc_disc_all_svcs(uint16_t conn_handle, ble_gatt_disc_svc_fn *cb,
STATS_INC(ble_gattc_stats, disc_all_svcs);
#if MYNEWT_VAL(BLE_GATT_CACHING)
rc = ble_gattc_cache_conn_search_all_svcs(conn_handle, cb, cb_arg);
if(rc == 0) {
return rc;
}
#endif
proc = ble_gattc_proc_alloc();
if (proc == NULL) {
rc = BLE_HS_ENOMEM;
@@ -1746,6 +1754,12 @@ ble_gattc_disc_svc_by_uuid(uint16_t conn_handle, const ble_uuid_t *uuid,
struct ble_gattc_proc *proc;
int rc;
#if MYNEWT_VAL(BLE_GATT_CACHING)
rc = ble_gattc_cache_conn_search_svc_by_uuid(conn_handle, uuid, cb, cb_arg);
if(rc == 0) {
return rc;
}
#endif
STATS_INC(ble_gattc_stats, disc_svc_uuid);
proc = ble_gattc_proc_alloc();
@@ -2290,6 +2304,12 @@ ble_gattc_disc_all_chrs(uint16_t conn_handle, uint16_t start_handle,
struct ble_gattc_proc *proc;
int rc;
#if MYNEWT_VAL(BLE_GATT_CACHING)
rc = ble_gattc_cache_conn_search_all_chrs(conn_handle, start_handle, end_handle, cb, cb_arg);
if(rc == 0) {
return rc;
}
#endif
STATS_INC(ble_gattc_stats, disc_all_chrs);
proc = ble_gattc_proc_alloc();
@@ -2529,6 +2549,12 @@ ble_gattc_disc_chrs_by_uuid(uint16_t conn_handle, uint16_t start_handle,
struct ble_gattc_proc *proc;
int rc;
#if MYNEWT_VAL(BLE_GATT_CACHING)
rc = ble_gattc_cache_conn_search_chrs_by_uuid(conn_handle, start_handle, end_handle, uuid, cb, cb_arg);
if(rc == 0) {
return rc;
}
#endif
STATS_INC(ble_gattc_stats, disc_chrs_uuid);
proc = ble_gattc_proc_alloc();
@@ -2739,6 +2765,12 @@ ble_gattc_disc_all_dscs(uint16_t conn_handle, uint16_t start_handle,
struct ble_gattc_proc *proc;
int rc;
#if MYNEWT_VAL(BLE_GATT_CACHING)
rc = ble_gattc_cache_conn_search_all_dscs(conn_handle, start_handle, end_handle, cb, cb_arg);
if(rc == 0) {
return rc;
}
#endif
STATS_INC(ble_gattc_stats, disc_all_dscs);
proc = ble_gattc_proc_alloc();
@@ -2796,6 +2828,11 @@ ble_gattc_read_cb(struct ble_gattc_proc *proc, int status,
STATS_INC(ble_gattc_stats, read_fail);
}
#if MYNEWT_VAL(BLE_GATT_CACHING)
if (status == BLE_HS_ATT_ERR(BLE_ATT_ERR_DB_OUT_OF_SYNC)) {
ble_gattc_cache_conn_update(proc->conn_handle, 0, 0xFFFF);
}
#endif
if (proc->read.cb == NULL) {
rc = 0;
} else {
@@ -3035,6 +3072,7 @@ ble_gattc_read_by_uuid(uint16_t conn_handle, uint16_t start_handle,
#if !MYNEWT_VAL(BLE_GATT_READ_UUID)
return BLE_HS_ENOTSUP;
#endif
/* TODO:Roshan */
struct ble_gattc_proc *proc;
int rc;
@@ -3095,6 +3133,11 @@ ble_gattc_read_long_cb(struct ble_gattc_proc *proc, int status,
STATS_INC(ble_gattc_stats, read_long_fail);
}
#if MYNEWT_VAL(BLE_GATT_CACHING)
if (status == BLE_HS_ATT_ERR(BLE_ATT_ERR_DB_OUT_OF_SYNC)) {
ble_gattc_cache_conn_update(proc->conn_handle, 0, 0xFFFF);
}
#endif
if (proc->read_long.cb == NULL) {
rc = 0;
} else {
@@ -3300,6 +3343,11 @@ ble_gattc_read_mult_cb(struct ble_gattc_proc *proc, int status,
attr.om = *om;
}
#if MYNEWT_VAL(BLE_GATT_CACHING)
if (status == BLE_HS_ATT_ERR(BLE_ATT_ERR_DB_OUT_OF_SYNC)) {
ble_gattc_cache_conn_update(proc->conn_handle, 0, 0xFFFF);
}
#endif
if (proc->read_mult.cb == NULL) {
rc = 0;
} else {
@@ -3472,6 +3520,11 @@ ble_gattc_write_cb(struct ble_gattc_proc *proc, int status,
STATS_INC(ble_gattc_stats, write_fail);
}
#if MYNEWT_VAL(BLE_GATT_CACHING)
if (status == BLE_HS_ATT_ERR(BLE_ATT_ERR_DB_OUT_OF_SYNC)) {
ble_gattc_cache_conn_update(proc->conn_handle, 0, 0xFFFF);
}
#endif
if (proc->write.cb == NULL) {
rc = 0;
} else {
@@ -3596,6 +3649,11 @@ ble_gattc_write_long_cb(struct ble_gattc_proc *proc, int status,
STATS_INC(ble_gattc_stats, write_long_fail);
}
#if MYNEWT_VAL(BLE_GATT_CACHING)
if (status == BLE_HS_ATT_ERR(BLE_ATT_ERR_DB_OUT_OF_SYNC)) {
ble_gattc_cache_conn_update(proc->conn_handle, 0, 0xFFFF);
}
#endif
if (proc->write_long.cb == NULL) {
rc = 0;
} else {
@@ -3892,6 +3950,11 @@ ble_gattc_write_reliable_cb(struct ble_gattc_proc *proc, int status,
STATS_INC(ble_gattc_stats, write_reliable_fail);
}
#if MYNEWT_VAL(BLE_GATT_CACHING)
if (status == BLE_HS_ATT_ERR(BLE_ATT_ERR_DB_OUT_OF_SYNC)) {
ble_gattc_cache_conn_update(proc->conn_handle, 0, 0xFFFF);
}
#endif
if (proc->write_reliable.cb == NULL) {
rc = 0;
} else {
@@ -4161,6 +4224,18 @@ done:
* $notify *
*****************************************************************************/
#if MYNEWT_VAL(BLE_GATT_CACHING)
static int ble_gatts_check_conn_aware(uint16_t conn_handle, bool *aware) {
struct ble_hs_conn *conn;
conn = ble_hs_conn_find(conn_handle);
if(conn == NULL) {
return BLE_HS_ENOTCONN;
}
*aware = conn->bhc_gatt_svr.aware_state;
return 0;
}
#endif
int
ble_gatts_notify_custom(uint16_t conn_handle, uint16_t chr_val_handle,
struct os_mbuf *txom)
@@ -4168,6 +4243,9 @@ ble_gatts_notify_custom(uint16_t conn_handle, uint16_t chr_val_handle,
#if !MYNEWT_VAL(BLE_GATT_NOTIFY)
return BLE_HS_ENOTSUP;
#endif
#if MYNEWT_VAL(BLE_GATT_CACHING)
bool aware;
#endif
int rc;
@@ -4175,6 +4253,18 @@ ble_gatts_notify_custom(uint16_t conn_handle, uint16_t chr_val_handle,
ble_gattc_log_notify(chr_val_handle);
#if MYNEWT_VAL(BLE_GATT_CACHING)
ble_hs_lock();
rc = ble_gatts_check_conn_aware(conn_handle, &aware);
ble_hs_unlock();
if(rc != 0) {
goto done;
}
if(!aware) {
rc = BLE_HS_EREJECT; /* TODO correct error code ?*/
goto done;
}
#endif
if (txom == NULL) {
/* No custom attribute data; read the value from the specified
* attribute.
@@ -4335,6 +4425,9 @@ ble_gatts_indicate_custom(uint16_t conn_handle, uint16_t chr_val_handle,
struct ble_gattc_proc *proc;
struct ble_hs_conn *conn;
int rc;
#if MYNEWT_VAL(BLE_GATT_CACHING)
bool aware;
#endif
STATS_INC(ble_gattc_stats, indicate);
@@ -4350,6 +4443,20 @@ ble_gatts_indicate_custom(uint16_t conn_handle, uint16_t chr_val_handle,
ble_gattc_log_indicate(chr_val_handle);
#if MYNEWT_VAL(BLE_GATT_CACHING)
if(chr_val_handle != ble_svc_gatt_changed_handle()) {
ble_hs_lock();
rc = ble_gatts_check_conn_aware(conn_handle, &aware);
ble_hs_unlock();
if(rc != 0) {
goto done;
}
if(!aware) {
rc = BLE_HS_EREJECT;
goto done;
}
}
#endif
if (txom == NULL) {
/* No custom attribute data; read the value from the specified
* attribute.
+728
View File
@@ -0,0 +1,728 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#include <assert.h>
#include <string.h>
#include "host/ble_hs.h"
#include "ble_hs_conn_priv.h"
#include "ble_hs_priv.h"
#include "ble_gattc_cache_priv.h"
#include "nimble/storage_port.h"
#include "host/ble_gatt.h"
#include "esp_nimble_mem.h"
#define GATT_CACHE_PREFIX "gatt_"
#define INVALID_ADDR_NUM 0xff
#define MAX_DEVICE_IN_CACHE 50
#define MAX_ADDR_LIST_CACHE_BUF 2048
#if MYNEWT_VAL(BLE_GATT_CACHING)
static const char *cache_key = "gattc_cache_key";
static const char *cache_addr = "cache_addr_tab";
static uint8_t ble_gattc_cache_find_addr(ble_addr_t addr);
static uint8_t ble_gattc_cache_find_hash(uint8_t * hash_key);
static uint8_t svc_end_handle;
struct cache_fn_mapping cache_fn;
typedef struct {
/*Save the service data in the list according to the address */
cache_handle_t cache_fp;
bool is_open;
ble_addr_t addr;
uint8_t hash_key[16];
} cache_addr_info_t;
typedef struct {
/* Save the address list in the cache */
cache_handle_t addr_fp;
bool is_open;
uint8_t num_addr;
cache_addr_info_t cache_addr[MAX_DEVICE_IN_CACHE];
} cache_env_t;
static cache_env_t *cache_env = NULL;
static void
print_hash_key(uint8_t * hash_key)
{
MODLOG_DFLT(DEBUG, "Hash Key : ");
for (int i = 0; i < 16; i++) {
MODLOG_DFLT(DEBUG, "%x ", hash_key[i]);
}
}
static void
print_addr(ble_addr_t addr)
{
MODLOG_DFLT(DEBUG, "Peer address: ");
for (int i = 0; i < 6; i++) {
MODLOG_DFLT(DEBUG, "%d ", addr.val[i]);
}
}
static void
getFilename(char *buffer, uint8_t * hash)
{
sprintf(buffer, "%s%02x%02x%02x%02x", GATT_CACHE_PREFIX,
hash[0], hash[1], hash[2], hash[3]);
}
static int
cacheErase(cache_handle_t handle)
{
if (cache_fn.erase_all) {
cache_fn.erase_all(handle);
}
return -1;
}
static int
cacheWrite(cache_handle_t handle, const char * key, const void* value, size_t length)
{
if (cache_fn.write) {
return cache_fn.write(handle, key, value, length);
}
return -1;
}
static int
cacheRead(cache_handle_t handle, const char * key, void* out_value, size_t* length)
{
if (cache_fn.read) {
return cache_fn.read(handle, key, out_value, length);
}
return -1;
}
static void
cacheClose(ble_addr_t addr)
{
uint8_t index = 0;
if ((index = ble_gattc_cache_find_addr(addr)) != INVALID_ADDR_NUM) {
if (cache_env->cache_addr[index].is_open) {
if (cache_fn.close) {
cache_fn.close(cache_env->cache_addr[index].cache_fp);
}
cache_env->cache_addr[index].is_open = false;
}
}
}
static bool
cacheOpen(ble_addr_t addr, bool to_save, uint8_t *index)
{
char fname[255] = {0};
int status = -1;
uint8_t hash_key[16] = {0};
if ((*index = ble_gattc_cache_find_addr(addr)) != INVALID_ADDR_NUM) {
if (cache_env->cache_addr[*index].is_open) {
return true;
} else {
memcpy(hash_key, cache_env->cache_addr[*index].hash_key, sizeof(uint8_t) * 16);
getFilename(fname, hash_key);
if (cache_fn.open) {
if ((status = cache_fn.open(fname, READWRITE, &cache_env->cache_addr[*index].cache_fp)) == 0) {
/* Set the open flag to TRUE when success to open the hash file. */
cache_env->cache_addr[*index].is_open = true;
}
}
}
}
return ((status == 0) ? true : false);
}
void
ble_gattc_cacheReset(ble_addr_t *addr)
{
uint8_t index = 0;
if (addr == NULL) {
BLE_HS_LOG(ERROR, "%s Cannot reset cache with null addr", __func__);
return;
}
if ((index = ble_gattc_cache_find_addr(*addr)) != INVALID_ADDR_NUM) {
if (cache_env->cache_addr[index].is_open) {
cacheErase(cache_env->cache_addr[index].cache_fp);
if (cache_fn.close) {
cache_fn.close(cache_env->cache_addr[index].cache_fp);
}
cache_env->cache_addr[index].is_open = false;
BLE_HS_LOG(DEBUG, "%s erased peer entry from NVS");
} else {
cacheOpen(*addr, false, &index);
if (index == INVALID_ADDR_NUM) {
BLE_HS_LOG(ERROR, "%s INVALID ADDR NUM", __func__);
return;
}
if (cache_env->cache_addr[index].is_open) {
cacheErase(cache_env->cache_addr[index].cache_fp);
if (cache_fn.close) {
cache_fn.close(cache_env->cache_addr[index].cache_fp);
}
cache_env->cache_addr[index].is_open = false;
BLE_HS_LOG(DEBUG, "%s erased peer entry from NVS");
} else {
BLE_HS_LOG(ERROR, "%s cacheOpen failed", __func__);
return;
}
}
if (cache_env->num_addr == 0) {
BLE_HS_LOG(ERROR, "%s cache addr list error", __func__);
return;
}
uint8_t num = cache_env->num_addr;
/* Delete the server_bda in the addr_info list. */
for (uint8_t i = index; i < (num - 1); i++) {
memcpy(&cache_env->cache_addr[i], &cache_env->cache_addr[i + 1],
sizeof(cache_addr_info_t));
}
/* Reduced the number address counter also */
cache_env->num_addr--;
/* Update addr list to storage flash */
if (cache_env->num_addr > 0) {
uint8_t *p_buf = nimble_platform_mem_malloc(MAX_ADDR_LIST_CACHE_BUF);
if (!p_buf) {
BLE_HS_LOG(ERROR, "%s malloc error", __func__);
return;
}
uint16_t length = cache_env->num_addr * (sizeof(ble_addr_t) + sizeof(uint8_t) * 16);
for (uint8_t i = 0; i < cache_env->num_addr; i++) {
/* Copy the address to the buffer. */
memcpy((p_buf + i * (sizeof(ble_addr_t) + sizeof(uint8_t) * 16)),
&cache_env->cache_addr[i].addr, sizeof(ble_addr_t));
/* Copy the hash key to the buffer.*/
memcpy(p_buf + i * (sizeof(ble_addr_t) + sizeof(uint8_t) * 16) + sizeof(ble_addr_t),
cache_env->cache_addr[i].hash_key, sizeof(uint8_t) * 16);
}
if (cache_env->is_open) {
if (cacheWrite(cache_env->addr_fp, cache_key, p_buf, length) != 0) {
BLE_HS_LOG(INFO, "%s, storage set blob failed", __func__);
}
}
nimble_platform_mem_free(p_buf);
} else {
if (cache_env->is_open) {
cacheErase(cache_env->addr_fp);
if (cache_fn.close) {
cache_fn.close(cache_env->addr_fp);
}
cache_env->is_open = false;
BLE_HS_LOG(DEBUG, "%s erased entire cache from NVS");
} else {
BLE_HS_LOG(INFO, "cache_env status is error");
}
}
}
}
static uint8_t
ble_gattc_cache_find_addr(ble_addr_t addr)
{
uint8_t addr_index = 0;
uint8_t num = cache_env->num_addr;
cache_addr_info_t *addr_info = &cache_env->cache_addr[0];
for (addr_index = 0; addr_index < num; addr_index++, addr_info++) {
if (!memcmp(&addr_info->addr, &addr, sizeof(ble_addr_t))) {
return addr_index;
}
}
return INVALID_ADDR_NUM;
}
static uint8_t
ble_gattc_cache_find_hash(uint8_t * hash_key)
{
uint8_t index = 0;
uint8_t num = cache_env->num_addr;
cache_addr_info_t *addr_info;
for (index = 0; index < num; index++) {
addr_info = &cache_env->cache_addr[index];
if (memcmp(addr_info->hash_key, hash_key, sizeof(uint8_t) * 16) == 0) {
return index;
}
}
return INVALID_ADDR_NUM;
}
static void check_uuid(ble_uuid_any_t *uuid)
{
ble_uuid16_t u16;
ble_uuid32_t u32;
switch (uuid->u.type) {
case BLE_UUID_TYPE_16:
u16 = *(const ble_uuid16_t *)uuid;
memset(uuid->u128.value, 0, sizeof(uuid->u128.value));
uuid->u16.u.type = u16.u.type;
uuid->u16.value = u16.value;
break;
case BLE_UUID_TYPE_32:
u32 = *(const ble_uuid32_t *)uuid;
memset(uuid->u128.value, 0, sizeof(uuid->u128.value));
uuid->u32.u.type = u32.u.type;
uuid->u32.value = u32.value;
break;
case BLE_UUID_TYPE_128:
break;
default:
assert(0);
break;
}
}
static void
ble_gattc_fill_nv_attr_entry(ble_uuid_any_t uuid, uint16_t s_handle, uint16_t e_handle,
ble_gatt_attr_type attr_type, bool is_primary,
struct ble_gatt_nv_attr *nv_attr, int index, uint8_t properties)
{
ble_uuid_copy(&nv_attr[index].uuid, &uuid.u);
check_uuid(&nv_attr[index].uuid);
nv_attr[index].s_handle = s_handle;
nv_attr[index].e_handle = e_handle;
nv_attr[index].is_primary = is_primary;
nv_attr[index].attr_type = attr_type;
nv_attr[index].properties = properties;
if (s_handle >= svc_end_handle) {
svc_end_handle = s_handle;
}
BLE_HS_LOG(DEBUG, "uuid = %x, s = %d, e = %d, is_primary = %d, attr_type = %d, prop =%d",
uuid.u16.value, s_handle, e_handle, is_primary, attr_type, properties);
}
static void
ble_gattc_fill_nv_attr(struct ble_gattc_cache_conn *peer, size_t num_attr, struct ble_gatt_nv_attr *nv_attr)
{
struct ble_gattc_cache_conn_svc *svc;
struct ble_gattc_cache_conn_chr *chr;
struct ble_gattc_cache_conn_dsc *dsc;
int index = 0;
int svc_index = 0;
SLIST_FOREACH(svc, &peer->svcs, next) {
ble_gattc_fill_nv_attr_entry(svc->svc.uuid, svc->svc.start_handle, svc->svc.end_handle,
BLE_GATT_ATTR_TYPE_SRVC, svc->type == BLE_GATT_SVC_TYPE_PRIMARY,
nv_attr, index, 0);
svc_index = index;
index++;
SLIST_FOREACH(chr, &svc->chrs, next) {
ble_gattc_fill_nv_attr_entry(chr->chr.uuid, chr->chr.val_handle,
chr->chr.def_handle, BLE_GATT_ATTR_TYPE_CHAR, false,
nv_attr, index, chr->chr.properties);
index++;
SLIST_FOREACH(dsc, &chr->dscs, next) {
ble_gattc_fill_nv_attr_entry(dsc->dsc.uuid, dsc->dsc.handle, 0,
BLE_GATT_ATTR_TYPE_CHAR_DESCR, false, nv_attr, index,
0);
index++;
}
}
if (svc->svc.end_handle == 65535) {
nv_attr[svc_index].e_handle = svc_end_handle;
}
}
}
static int
ble_gattc_cache_addr_save(uint8_t *out_index, ble_addr_t addr, uint8_t * hash_key)
{
int rc;
uint8_t num = ++(cache_env->num_addr);
uint8_t index = 0;
uint8_t insert_ind = 0;
uint8_t i = 0;
uint8_t *p_buf;
p_buf = nimble_platform_mem_malloc(MAX_ADDR_LIST_CACHE_BUF);
if (p_buf == NULL) {
return BLE_HS_ENOMEM;
}
/* Check the address list has the same hash key or not */
if (ble_gattc_cache_find_hash(hash_key) != INVALID_ADDR_NUM) {
BLE_HS_LOG(DEBUG, "Hash key already present in the cache list");
if ((index = ble_gattc_cache_find_addr(addr)) != INVALID_ADDR_NUM) {
BLE_HS_LOG(DEBUG, "tBD address already present in the cache list");
/* If the bd_addr already in the address list, update the hash key in it. */
insert_ind = index;
} else {
/*
If the bd_addr isn't in the address list, added the bd_addr to the last of the
address list.
*/
if(num > MYNEWT_VAL(BLE_GATT_CACHING_MAX_CONNS)) {
return BLE_HS_ENOMEM;
}
BLE_HS_LOG(DEBUG, "BD addr not present");
insert_ind = num - 1;
}
} else {
BLE_HS_LOG(DEBUG, "Hash key not present, saving new data");
if(num > MYNEWT_VAL(BLE_GATT_CACHING_MAX_CONNS)) {
return BLE_HS_ENOMEM;
}
insert_ind = num - 1;
}
print_hash_key(hash_key);
print_addr(addr);
memcpy(cache_env->cache_addr[insert_ind].hash_key, hash_key, sizeof(uint8_t) * 16);
memcpy(&cache_env->cache_addr[insert_ind].addr, &addr, sizeof(ble_addr_t));
cache_handle_t *fp = &cache_env->addr_fp;
uint16_t length = num * (sizeof(ble_addr_t) + (sizeof(uint8_t) * 16));
for (i = 0; i < num; i++) {
memcpy(p_buf + i * (sizeof(ble_addr_t) + sizeof(uint8_t) * 16),
&cache_env->cache_addr[i].addr, sizeof(ble_addr_t));
memcpy(p_buf + i * (sizeof(ble_addr_t) + sizeof(uint8_t) * 16) + sizeof(ble_addr_t),
cache_env->cache_addr[i].hash_key, sizeof(uint8_t) * 16);
}
if (cache_env->is_open) {
BLE_HS_LOG(DEBUG, "NVS Opened already");
rc = cacheWrite(cache_env->addr_fp, cache_key, p_buf, length);
if (rc != 0) {
BLE_HS_LOG(ERROR, "storage set blob fail, err %d", rc);
}
} else {
rc = cache_fn.open(cache_addr, READWRITE, fp);
if (rc == 0) {
cache_env->is_open = true;
rc = cacheWrite(cache_env->addr_fp, cache_key, p_buf, length);
if (rc != 0) {
BLE_HS_LOG(ERROR, "storage set blob fail, err %d", rc);
}
} else {
BLE_HS_LOG(ERROR, "Line = %d, storage flash open fail, err_code = %x",
__LINE__, rc);
}
}
nimble_platform_mem_free(p_buf);
if(out_index) {
*out_index = insert_ind;
}
return rc;
}
static int
handle_compare(const void *s1, const void *s2)
{
return ((struct ble_gatt_nv_attr *)s1)->s_handle - ((struct ble_gatt_nv_attr *)s2)->s_handle;
}
static void
ble_gatts_sort_nv_attr(struct ble_gatt_nv_attr *nv_attr, size_t num_attr)
{
qsort(nv_attr, (num_attr), sizeof(struct ble_gatt_nv_attr), handle_compare);
}
void
ble_gattc_cache_save(struct ble_gattc_cache_conn *peer, size_t num_attr)
{
int rc = 0;
uint8_t hash_key[16] = {0};
uint8_t index = INVALID_ADDR_NUM;
struct ble_gatt_nv_attr *nv_attr;
nv_attr = (struct ble_gatt_nv_attr *) nimble_platform_mem_malloc(num_attr * sizeof(ble_gatt_nv_attr));
if (nv_attr == NULL) {
BLE_HS_LOG(DEBUG, "Failed to allocate memory to nv_attr");
return;
}
memset(nv_attr, 0, num_attr * sizeof(ble_gatt_nv_attr));
ble_gattc_fill_nv_attr(peer, num_attr, nv_attr);
ble_gatts_sort_nv_attr(nv_attr, num_attr);
memcpy(hash_key, &peer->database_hash, sizeof(uint8_t) * 16);
rc = ble_gattc_cache_addr_save(&index, peer->ble_gattc_cache_conn_addr, hash_key);
if(rc != 0) {
/* cannot save address, return */
BLE_HS_LOG(ERROR, "Failed to save cache %d", rc);
return;
}
if (cacheOpen(peer->ble_gattc_cache_conn_addr, true, &index)) {
BLE_HS_LOG(DEBUG, "Cache Opened already \n\tWriting cache_fp and cache_key on index = %d",
index);
rc = cacheWrite(cache_env->cache_addr[index].cache_fp, cache_key, nv_attr,
num_attr * sizeof(struct ble_gatt_nv_attr));
} else {
rc = -1;
}
BLE_HS_LOG(INFO, "%s() wrote hash_key on index = %d, num_attr = %d, status = %d.", __func__,
index, num_attr, rc);
nimble_platform_mem_free(nv_attr);
cacheClose(peer->ble_gattc_cache_conn_addr);
}
static struct ble_gatt_nv_attr *
ble_gattc_cache_load_nv_attr(uint8_t index, int *num_attr)
{
int rc;
size_t length = 0;
struct ble_gatt_nv_attr *nv_attr;
cacheRead(cache_env->cache_addr[index].cache_fp, cache_key, NULL, &length);
*num_attr = length / (sizeof(ble_gatt_nv_attr));
nv_attr = (struct ble_gatt_nv_attr *) nimble_platform_mem_malloc((*num_attr) * sizeof(struct ble_gatt_nv_attr));
if (nv_attr == NULL) {
return NULL;
}
rc = cacheRead(cache_env->cache_addr[index].cache_fp, cache_key, nv_attr, &length);
BLE_HS_LOG(INFO, "%s, rc = %d, length = %d index = %d", __func__, rc, length, index);
return nv_attr;
}
static int
ble_gattc_add_svc_from_cache(ble_addr_t peer_addr, struct ble_gatt_nv_attr nv_attr)
{
struct ble_gatt_svc *gatt_svc;
gatt_svc = (struct ble_gatt_svc *)nimble_platform_mem_malloc(sizeof(struct ble_gatt_svc));
if (gatt_svc == NULL) {
return BLE_HS_ENOMEM;
}
gatt_svc->start_handle = nv_attr.s_handle;
gatt_svc->end_handle = nv_attr.e_handle;
ble_uuid_copy(&gatt_svc->uuid, &nv_attr.uuid.u);
return ble_gattc_cache_conn_svc_add(peer_addr, gatt_svc);
}
static int
ble_gattc_add_inc_from_cache(ble_addr_t peer_addr, struct ble_gatt_nv_attr nv_attr)
{
struct ble_gatt_svc *gatt_svc;
gatt_svc = (struct ble_gatt_svc *)nimble_platform_mem_malloc(sizeof(struct ble_gatt_svc));
if (gatt_svc == NULL) {
return BLE_HS_ENOMEM;
}
gatt_svc->start_handle = nv_attr.s_handle;
gatt_svc->end_handle = nv_attr.e_handle;
ble_uuid_copy(&gatt_svc->uuid, &nv_attr.uuid.u);
return ble_gattc_cache_conn_inc_add(peer_addr, gatt_svc);
}
static int
ble_gattc_add_chr_from_cache(ble_addr_t peer_addr, struct ble_gatt_nv_attr nv_attr)
{
struct ble_gatt_chr *gatt_chr;
gatt_chr = (struct ble_gatt_chr *)nimble_platform_mem_malloc(sizeof(struct ble_gatt_chr));
if (gatt_chr == NULL) {
return BLE_HS_ENOMEM;
}
gatt_chr->val_handle = nv_attr.s_handle;
gatt_chr->def_handle = nv_attr.e_handle;
ble_uuid_copy(&gatt_chr->uuid, &nv_attr.uuid.u);
gatt_chr->properties = nv_attr.properties;
return ble_gattc_cache_conn_chr_add(peer_addr, 0, gatt_chr);
}
static int
ble_gattc_add_dsc_from_cache(ble_addr_t peer_addr, struct ble_gatt_nv_attr nv_attr)
{
struct ble_gatt_dsc *gatt_dsc;
gatt_dsc = (struct ble_gatt_dsc *)nimble_platform_mem_malloc(sizeof(struct ble_gatt_dsc));
if (gatt_dsc == NULL) {
return BLE_HS_ENOMEM;
}
gatt_dsc->handle = nv_attr.s_handle;
ble_uuid_copy(&gatt_dsc->uuid, &nv_attr.uuid.u);
return ble_gattc_cache_conn_dsc_add(peer_addr, 0, gatt_dsc);
}
int
ble_gattc_cache_load(ble_addr_t peer_addr)
{
uint8_t index = 0;
uint8_t cache_index = 0;
int num_attr = 50;
int rc = 0;
struct ble_gatt_nv_attr *nv_attr;
if (!cacheOpen(peer_addr, true, &index)) {
BLE_HS_LOG(INFO, "gattc cache open fail");
return BLE_HS_EINVAL;
}
if ((nv_attr = ble_gattc_cache_load_nv_attr(index, &num_attr)) == NULL) {
BLE_HS_LOG(INFO, "%s, gattc cache nv_attr load fail", __func__);
return BLE_HS_EINVAL;
}
for (int i = 0; i < num_attr; i++) {
switch (nv_attr[i].attr_type) {
case BLE_GATT_ATTR_TYPE_SRVC:
if (nv_attr[i].is_primary) {
rc = ble_gattc_add_svc_from_cache(peer_addr, nv_attr[i]);
} else {
rc = ble_gattc_add_inc_from_cache(peer_addr, nv_attr[i]);
}
break;
case BLE_GATT_ATTR_TYPE_CHAR:
rc = ble_gattc_add_chr_from_cache(peer_addr, nv_attr[i]);
break;
case BLE_GATT_ATTR_TYPE_CHAR_DESCR:
rc = ble_gattc_add_dsc_from_cache(peer_addr, nv_attr[i]);
break;
default:
break;
}
}
nimble_platform_mem_free(nv_attr);
cache_index = ble_gattc_cache_find_addr(peer_addr);
ble_gattc_cache_conn_load_hash(cache_env->cache_addr[cache_index].addr,
cache_env->cache_addr[cache_index].hash_key);
return rc;
}
int
ble_gattc_cache_check_hash(struct ble_gattc_cache_conn *peer, struct os_mbuf *om)
{
if (peer == NULL || om == NULL) {
BLE_HS_LOG(ERROR, "Check hash failed");
return -1;
}
if (memcmp(peer->database_hash, om->om_data, om->om_len) == 0) {
return 0;
}
return -1;
}
int
ble_gattc_cache_init(void *storage_cb)
{
/* Point where to store data */
cache_fn = link_storage_fn(storage_cb);
cache_handle_t fp;
int rc = 0;
uint8_t num_addr;
size_t length = MAX_ADDR_LIST_CACHE_BUF;
svc_end_handle = 0;
uint8_t *p_buf = nimble_platform_mem_malloc(MAX_ADDR_LIST_CACHE_BUF);
if (p_buf == NULL) {
BLE_HS_LOG(ERROR, "%s malloc failed!", __func__);
rc = BLE_HS_ENOMEM;
return rc;
}
cache_env = (cache_env_t *)nimble_platform_mem_malloc(sizeof(cache_env_t));
if (cache_env == NULL) {
BLE_HS_LOG(ERROR, "%s malloc failed!", __func__);
nimble_platform_mem_free(p_buf);
rc = BLE_HS_ENOMEM;
return rc;
}
memset(cache_env, 0x0, sizeof(cache_env_t));
if (cache_fn.open) {
if ((rc = cache_fn.open(cache_addr, READWRITE, &fp)) == 0) {
cache_env->addr_fp = fp;
cache_env->is_open = true;
/* Read previously saved blob if available */
if ((rc = cacheRead(fp, cache_key, p_buf, &length)) != 0) {
if (rc != 0) {
BLE_HS_LOG(DEBUG, "%s, Line = %d, storage flash get blob data fail, err_code = 0x%x",
__func__, __LINE__, rc);
}
nimble_platform_mem_free(p_buf);
return rc;
}
num_addr = length / (sizeof(ble_addr_t) + sizeof(uint8_t) * 16);
cache_env->num_addr = num_addr;
BLE_HS_LOG(DEBUG, "Number of address loaded = %d", cache_env->num_addr);
/* Read the address from storage flash to cache address list. */
for (uint8_t i = 0; i < num_addr; i++) {
memcpy(&cache_env->cache_addr[i].addr,
p_buf + i * (sizeof(ble_addr_t) + sizeof(uint8_t) * 16), sizeof(ble_addr_t));
memcpy(cache_env->cache_addr[i].hash_key,
p_buf + i * (sizeof(ble_addr_t) + sizeof(uint8_t) * 16) + sizeof(ble_addr_t),
sizeof(uint8_t) * 16);
print_addr(cache_env->cache_addr[i].addr);
print_hash_key(cache_env->cache_addr[i].hash_key);
}
}
} else {
BLE_HS_LOG(ERROR, "%s, Line = %d, storage flash open fail, err_code = %x", __func__, __LINE__,
rc);
nimble_platform_mem_free(p_buf);
return rc;
}
nimble_platform_mem_free(p_buf);
return 0;
}
#endif /* MYNEWT_VAL(BLE_GATT_CACHING) */
File diff suppressed because it is too large Load Diff
+184
View File
@@ -0,0 +1,184 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#ifndef H_BLE_GATTC_CACHE_PRIV_
#define H_BLE_GATTC_CACHE_PRIV_
#include "modlog/modlog.h"
#include "sys/queue.h"
#include "host/ble_gatt.h"
#include "nimble/ble.h"
#include "services/gatt/ble_svc_gatt.h"
#ifdef __cplusplus
extern "C" {
#endif
#if MYNEWT_VAL(BLE_GATT_CACHING)
#define BLE_GATTC_DATABASE_HASH_UUID128 0x2b2a
enum {
BLE_GATT_ATTR_TYPE_INCL_SRVC,
BLE_GATT_ATTR_TYPE_CHAR,
BLE_GATT_ATTR_TYPE_CHAR_DESCR,
BLE_GATT_ATTR_TYPE_SRVC
};
typedef uint8_t ble_gatt_attr_type;
typedef struct ble_gatt_nv_attr {
uint16_t s_handle;
uint16_t e_handle; /* used for service only */
ble_gatt_attr_type attr_type;
ble_uuid_any_t uuid;
uint8_t properties; /* used for characteristic only */
unsigned int is_primary : 1; /* used for service only */
} ble_gatt_nv_attr;
/* cache conn */
/** ble_gattc_cache_conn. */
struct ble_gattc_cache_conn_dsc {
SLIST_ENTRY(ble_gattc_cache_conn_dsc) next;
struct ble_gatt_dsc dsc;
};
SLIST_HEAD(ble_gattc_cache_conn_dsc_list, ble_gattc_cache_conn_dsc);
struct ble_gattc_cache_conn_chr {
SLIST_ENTRY(ble_gattc_cache_conn_chr) next;
struct ble_gatt_chr chr;
struct ble_gattc_cache_conn_dsc_list dscs;
};
SLIST_HEAD(ble_gattc_cache_conn_chr_list, ble_gattc_cache_conn_chr);
struct ble_gattc_cache_conn_svc {
SLIST_ENTRY(ble_gattc_cache_conn_svc) next;
/**
* One of the following:
* o BLE_GATT_SVC_TYPE_PRIMARY - primary service
* o BLE_GATT_SVC_TYPE_SECONDARY - secondary service
*/
uint8_t type;
struct ble_gatt_svc svc;
struct ble_gattc_cache_conn_chr_list chrs;
};
SLIST_HEAD(ble_gattc_cache_conn_svc_list, ble_gattc_cache_conn_svc);
struct ble_gattc_cache_conn;
typedef void ble_gattc_cache_conn_disc_fn(const struct ble_gattc_cache_conn *ble_gattc_cache_conn, int status, void *arg);
enum {
CACHE_INVALID = 0,
CACHE_LOADED,
CACHE_VERIFIED,
SVC_DISC_IN_PROGRESS,
CHR_DISC_IN_PROGRESS,
INC_DISC_IN_PROGRESS,
DSC_DISC_IN_PROGRESS,
VERIFY_IN_PROGRESS
};
struct ble_gattc_cache_conn_op {
/* cb is used only when the gattc
request comes while the cache is building */
uint16_t start_handle;
uint16_t end_handle;
ble_uuid_t uuid;
void *cb;
void *cb_arg;
uint8_t cb_type;
};
struct ble_gattc_cache_conn {
SLIST_ENTRY(ble_gattc_cache_conn) next;
uint16_t conn_handle;
ble_addr_t ble_gattc_cache_conn_addr;
uint8_t database_hash[16];
/** List of discovered GATT services. */
struct ble_gattc_cache_conn_svc_list svcs;
uint8_t cache_state;
/** Keeps track of where we are in the service discovery process. */
uint16_t disc_prev_chr_val;
struct ble_gattc_cache_conn_svc *cur_svc;
struct ble_gattc_cache_conn_op pending_op;
/* event to be posted to inform
the application about the discovery results */
struct ble_npl_event disc_ev;
};
/* apis from gatt service */
uint16_t ble_svc_gatt_changed_handle();
uint16_t ble_svc_gatt_hash_handle();
uint16_t ble_svc_gatt_csf_handle();
uint8_t ble_svc_gatt_get_csfs();
#if MYNEWT_VAL(BLE_DYNAMIC_SERVICE)
void ble_svc_gatt_changed(uint16_t start_handle, uint16_t end_handle);
#endif
int ble_gattc_cache_conn_add(uint16_t conn_handle, ble_addr_t ble_gattc_cache_conn_addr);
int ble_gattc_cache_conn_svc_add(ble_addr_t peer_addr, const struct ble_gatt_svc *gatt_svc);
int ble_gattc_cache_conn_inc_add(ble_addr_t peer_addr, const struct ble_gatt_svc *gatt_svc);
int ble_gattc_cache_conn_chr_add(ble_addr_t peer_addr, uint16_t svc_start_handle,
const struct ble_gatt_chr *gatt_chr);
int ble_gattc_cache_conn_dsc_add(ble_addr_t peer_addr, uint16_t chr_val_handle,
const struct ble_gatt_dsc *gatt_dsc);
/**
* Loads the cache for the connection given by conn_handle
*/
int ble_gattc_cache_conn_create(uint16_t conn_handle, ble_addr_t ble_gattc_cache_conn_addr);
void ble_gattc_cache_conn_load_hash(ble_addr_t peer_addr, uint8_t *hash_key);
void ble_gattc_cache_conn_update(uint16_t conn_handle, uint16_t start_handle, uint16_t end_handle);
uint16_t ble_gattc_cache_conn_get_svc_changed_handle(uint16_t conn_handle);
/* cache store */
void ble_gattc_cache_save(struct ble_gattc_cache_conn *peer, size_t num_attr);
int ble_gattc_cache_init(void *storage_cb);
int ble_gattc_cache_load(ble_addr_t peer_addr);
int ble_gattc_cache_check_hash(struct ble_gattc_cache_conn *peer, struct os_mbuf *om);
void ble_gattc_cacheReset(ble_addr_t *addr);
void ble_gattc_cache_conn_broken(uint16_t conn_handle);
void ble_gattc_cache_conn_bonding_established(uint16_t conn_handle);
void ble_gattc_cache_conn_bonding_restored(uint16_t conn_handle);
/* cache search */
int ble_gattc_cache_conn_search_all_svcs(uint16_t conn_handle,
ble_gatt_disc_svc_fn *cb, void *cb_arg);
int ble_gattc_cache_conn_search_svc_by_uuid(uint16_t conn_handle, const ble_uuid_t *uuid,
ble_gatt_disc_svc_fn *cb, void *cb_arg);
int ble_gattc_cache_conn_search_inc_svcs(uint16_t conn_handle, uint16_t start_handle,
uint16_t end_handle,
ble_gatt_disc_svc_fn *cb, void *cb_arg);
int ble_gattc_cache_conn_search_all_chrs(uint16_t conn_handle, uint16_t start_handle,
uint16_t end_handle, ble_gatt_chr_fn *cb,
void *cb_arg);
int ble_gattc_cache_conn_search_chrs_by_uuid(uint16_t conn_handle, uint16_t start_handle,
uint16_t end_handle, const ble_uuid_t *uuid,
ble_gatt_chr_fn *cb, void *cb_arg);
int
ble_gattc_cache_conn_search_all_dscs(uint16_t conn_handle, uint16_t start_handle,
uint16_t end_handle,
ble_gatt_dsc_fn *cb, void *cb_arg);
#ifdef __cplusplus
}
#endif
#endif
#endif
+223 -5
View File
@@ -43,6 +43,12 @@ enum {
};
#endif
#if MYNEWT_VAL(BLE_GATT_CACHING)
/* store the aware state only for the bonded peers */
struct ble_gatts_aware_state ble_gatts_conn_aware_states[MYNEWT_VAL(BLE_STORE_MAX_BONDS)];
/* index of latest bonded peer */
static int last_conn_aware_state_index;
#endif
static const ble_uuid_t *uuid_pri =
BLE_UUID16_DECLARE(BLE_ATT_UUID_PRIMARY_SERVICE);
static const ble_uuid_t *uuid_sec =
@@ -571,6 +577,42 @@ ble_gatts_svc_incs_satisfied(const struct ble_gatt_svc_def *svc)
return 1;
}
#if MYNEWT_VAL(BLE_GATT_CACHING)
int
ble_gatts_calculate_hash(uint8_t *out_hash_key)
{
int size;
int rc;
uint8_t *buf;
uint8_t key[16] = {0};
/* data with all zeroes */
rc = ble_att_get_database_size(&size);
if(rc != 0) {
return rc;
}
buf = nimble_platform_mem_malloc(sizeof(uint8_t) * size);
if(buf == NULL) {
rc = BLE_HS_ENOMEM;
return rc;
}
rc = ble_att_fill_database_info(buf);
if(rc != 0) {
return rc;
}
rc = ble_sm_alg_aes_cmac(key, buf, size, out_hash_key);
if(rc != 0) {
return rc;
}
swap_in_place(out_hash_key, 16);
return 0;
}
#endif
static int
ble_gatts_register_inc(struct ble_gatts_svc_entry *entry)
{
@@ -1285,6 +1327,11 @@ ble_gatts_connection_broken(uint16_t conn_handle)
int i;
#endif
#if MYNEWT_VAL(BLE_GATT_CACHING)
struct ble_hs_conn_addrs addrs;
int i;
#endif
/* Find the specified connection and extract its CCCD entries. Extracting
* the clt_cfg pointer and setting the original to null is done for two
* reasons:
@@ -1310,6 +1357,19 @@ ble_gatts_connection_broken(uint16_t conn_handle)
conn->bhc_gatt_svr.clt_cfgs = NULL;
#endif
conn->bhc_gatt_svr.num_clt_cfgs = 0;
#if MYNEWT_VAL(BLE_GATT_CACHING)
/* update bonded peer aware state */
if(conn->bhc_sec_state.bonded) {
ble_hs_conn_addrs(conn, &addrs);
for(i = 0; i < MYNEWT_VAL(BLE_STORE_MAX_BONDS); i++) {
if(memcmp(ble_gatts_conn_aware_states[i].peer_id_addr,
addrs.peer_id_addr.val, sizeof addrs.peer_id_addr.val)) {
ble_gatts_conn_aware_states[i].aware = conn->bhc_gatt_svr.aware_state;
}
}
}
#endif
}
ble_hs_unlock();
@@ -1744,6 +1804,11 @@ ble_gatts_rx_indicate_ack(uint16_t conn_handle, uint16_t chr_val_handle)
#endif
int persist;
int rc;
#if MYNEWT_VAL(BLE_GATT_CACHING)
uint16_t svc_change_handle;
svc_change_handle = ble_svc_gatt_changed_handle();
#endif
#if MYNEWT_VAL(BLE_DYNAMIC_SERVICE)
clt_cfg = ble_gatts_clt_cfg_find(&ble_gatts_clt_cfgs,
@@ -1782,6 +1847,11 @@ ble_gatts_rx_indicate_ack(uint16_t conn_handle, uint16_t chr_val_handle)
* been modified since we sent the indication, there is no indication
* pending.
*/
#if MYNEWT_VAL(BLE_GATT_CACHING)
if(chr_val_handle == svc_change_handle) {
conn->bhc_gatt_svr.aware_state = true;
}
#endif
#if MYNEWT_VAL(BLE_DYNAMIC_SERVICE)
clt_cfg = ble_gatts_clt_cfg_find(&conn->bhc_gatt_svr.clt_cfgs, chr_val_handle);
BLE_HS_DBG_ASSERT(clt_cfg != NULL);
@@ -1943,6 +2013,92 @@ ble_gatts_chr_updated(uint16_t chr_val_handle)
}
}
int
ble_gatts_peer_cl_sup_feat_get(uint16_t conn_handle, uint8_t *out_supported_feat, uint8_t len)
{
struct ble_hs_conn *conn;
int rc = 0;
if (out_supported_feat == NULL) {
return BLE_HS_EINVAL;
}
ble_hs_lock();
conn = ble_hs_conn_find(conn_handle);
if (conn == NULL) {
rc = BLE_HS_ENOTCONN;
goto done;
}
if (BLE_GATT_CHR_CLI_SUP_FEAT_SZ < len) {
len = BLE_GATT_CHR_CLI_SUP_FEAT_SZ;
}
memcpy(out_supported_feat, conn->bhc_gatt_svr.peer_cl_sup_feat,
sizeof(uint8_t) * len);
done:
ble_hs_unlock();
return rc;
}
int
ble_gatts_peer_cl_sup_feat_update(uint16_t conn_handle, struct os_mbuf *om)
{
struct ble_hs_conn *conn;
uint8_t feat[BLE_GATT_CHR_CLI_SUP_FEAT_SZ] = {};
uint16_t len;
int rc = 0;
int i;
int rfu_mask = 7;
BLE_HS_LOG(DEBUG, "");
if (!om) {
return BLE_HS_EINVAL;
}
/* RFU bits are ignored so we can skip any bytes larger than supported */
len = os_mbuf_len(om);
if (len > BLE_GATT_CHR_CLI_SUP_FEAT_SZ) {
len = BLE_GATT_CHR_CLI_SUP_FEAT_SZ;
}
if (os_mbuf_copydata(om, 0, len, feat) < 0) {
return BLE_ATT_ERR_UNLIKELY;
}
/* clear RFU bits */
for (i = 0; i < BLE_GATT_CHR_CLI_SUP_FEAT_SZ; i++) {
feat[i] &= (BLE_GATT_CHR_CLI_SUP_FEAT_MASK >> (8 * i));
}
ble_hs_lock();
conn = ble_hs_conn_find(conn_handle);
if (conn == NULL) {
rc = BLE_HS_ENOTCONN;
goto done;
}
/**
* Disabling already enabled features is not permitted
* (Vol. 3, Part F, 3.3.3)
*/
for (i = 0; i < BLE_GATT_CHR_CLI_SUP_FEAT_SZ; i++) {
if ((conn->bhc_gatt_svr.peer_cl_sup_feat[i] & feat[i]) !=
conn->bhc_gatt_svr.peer_cl_sup_feat[i]) {
rc = BLE_ATT_ERR_VALUE_NOT_ALLOWED;
goto done;
}
}
memcpy(conn->bhc_gatt_svr.peer_cl_sup_feat, feat, BLE_GATT_CHR_CLI_SUP_FEAT_SZ);
done:
ble_hs_unlock();
return rc;
}
/**
* Sends notifications or indications for the specified characteristic to all
* connected devices. The bluetooth spec does not allow more than one
@@ -2058,6 +2214,10 @@ ble_gatts_bonding_established(uint16_t conn_handle)
#if !MYNEWT_VAL(BLE_DYNAMIC_SERVICE)
int i;
#endif
#if MYNEWT_VAL(BLE_GATT_CACHING)
struct ble_hs_conn_addrs addrs;
int new_idx;
#endif
ble_hs_lock();
@@ -2092,6 +2252,19 @@ ble_gatts_bonding_established(uint16_t conn_handle)
}
}
#if MYNEWT_VAL(BLE_GATT_CACHING)
/* store the bonded peer aware_state
if space not available delete the
oldest bond */
ble_hs_conn_addrs(conn, &addrs);
new_idx = (last_conn_aware_state_index + 1) %
MYNEWT_VAL(BLE_STORE_MAX_BONDS);
memset(&ble_gatts_conn_aware_states[new_idx], 0,
sizeof(struct ble_gatts_aware_state));
memcpy(ble_gatts_conn_aware_states[new_idx].peer_id_addr,
addrs.peer_id_addr.val, sizeof addrs.peer_id_addr.val);
last_conn_aware_state_index = new_idx;
#endif
ble_hs_unlock();
}
@@ -2112,6 +2285,10 @@ ble_gatts_bonding_restored(uint16_t conn_handle)
struct ble_hs_conn *conn;
uint8_t att_op;
int rc;
#if MYNEWT_VAL(BLE_GATT_CACHING)
struct ble_hs_conn_addrs addrs;
int i;
#endif
ble_hs_lock();
@@ -2125,6 +2302,16 @@ ble_gatts_bonding_restored(uint16_t conn_handle)
cccd_key.chr_val_handle = 0;
cccd_key.idx = 0;
#if MYNEWT_VAL(BLE_GATT_CACHING)
/* update the aware state of the client */
ble_hs_conn_addrs(conn, &addrs);
for(i = 0; i < MYNEWT_VAL(BLE_STORE_MAX_BONDS); i++) {
if(memcmp(ble_gatts_conn_aware_states[i].peer_id_addr,
addrs.peer_id_addr.val, sizeof addrs.peer_id_addr.val)) {
conn->bhc_gatt_svr.aware_state = ble_gatts_conn_aware_states[i].aware;
}
}
#endif
ble_hs_unlock();
while (1) {
@@ -2393,12 +2580,20 @@ static void ble_gatts_remove_clt_cfg(struct ble_gatts_clt_cfg_list *clt_cfgs, ui
}
}
#if MYNEWT_VAL(BLE_GATT_CACHING)
static int
ble_gatts_conn_unaware(struct ble_hs_conn *conn, void *arg) {
conn->bhc_gatt_svr.aware_state = false;
return 0;
}
#endif
/* takes two arguments
arg[0] : added/removed
arg[1] : affected chr_val_handle
arg[2] : allowed_flags
*/
static int update_conn_clt_cfg(struct ble_hs_conn *conn, void *arg) {
static int ble_gatts_update_conn_clt_cfg(struct ble_hs_conn *conn, void *arg) {
uint16_t action = ((uint16_t *) arg)[0];
uint16_t chr_val_handle = ((uint16_t *) arg)[1];
uint16_t allowed_flags;
@@ -2474,10 +2669,9 @@ int ble_gatts_add_dynamic_svcs(const struct ble_gatt_svc_def *svcs) {
arg[0] = CONN_CLT_CFG_ADD;
arg[1] = ha->ha_handle_id + 1;
arg[2] = allowed_flags;
ble_hs_conn_foreach(update_conn_clt_cfg, arg);
ble_hs_conn_foreach(ble_gatts_update_conn_clt_cfg, arg);
}
}
/* send service change indication */
i = 0;
entry = ble_gatts_find_svc_entry(&svcs[i]);
start_handle = entry->handle;
@@ -2486,6 +2680,15 @@ int ble_gatts_add_dynamic_svcs(const struct ble_gatt_svc_def *svcs) {
}
entry = ble_gatts_find_svc_entry(&svcs[i - 1]);
end_handle = entry->end_group_handle;
#if MYNEWT_VAL(BLE_GATT_CACHING)
/* make all bonded connections unaware */
for(i = 0; i < MYNEWT_VAL(BLE_STORE_MAX_BONDS); i++) {
ble_gatts_conn_aware_states[i].aware = false;
}
ble_hs_conn_foreach(ble_gatts_conn_unaware, NULL);
#endif
/* send service change indication */
ble_svc_gatt_changed(start_handle, end_handle);
done:
ble_hs_unlock();
@@ -2538,6 +2741,10 @@ int ble_gatts_delete_svc(const ble_uuid_t *uuid) {
ble_uuid16_t uuid_chr = BLE_UUID16_INIT(BLE_ATT_UUID_CHARACTERISTIC);
struct ble_att_svr_entry *ha;
uint16_t start_handle, end_handle;
#if MYNEWT_VAL(BLE_GATT_CACHING)
int i;
#endif
/* Update the cache. and connections*/
ble_hs_lock();
entry = ble_gatts_find_svc_entry_by_uuid(uuid);
@@ -2560,7 +2767,7 @@ int ble_gatts_delete_svc(const ble_uuid_t *uuid) {
/* update connections */
arg[0] = CONN_CLT_CFG_REMOVE;
arg[1] = chr_val_handle;
ble_hs_conn_foreach(update_conn_clt_cfg, arg);
ble_hs_conn_foreach(ble_gatts_update_conn_clt_cfg, arg);
}
}
/* keep the start handle and end handle before deleting the service */
@@ -2573,6 +2780,14 @@ int ble_gatts_delete_svc(const ble_uuid_t *uuid) {
done:
if (rc == 0) {
rc = ble_gatts_remove_svc_entry(uuid);
#if MYNEWT_VAL(BLE_GATT_CACHING)
/* make all bonded connections them unaware */
for(i = 0; i < MYNEWT_VAL(BLE_STORE_MAX_BONDS); i++) {
ble_gatts_conn_aware_states[i].aware = false;
}
ble_hs_conn_foreach(ble_gatts_conn_unaware, NULL);
#endif
/* send service change indication */
ble_svc_gatt_changed(start_handle, end_handle);
}
@@ -2848,7 +3063,10 @@ ble_gatts_init(void)
#if MYNEWT_VAL(BLE_DYNAMIC_SERVICE)
STAILQ_INIT(&ble_gatts_svc_entries);
#endif
#if MYNEWT_VAL(BLE_GATT_CACHING)
memset(ble_gatts_conn_aware_states, 0, sizeof ble_gatts_conn_aware_states);
last_conn_aware_state_index = 0;
#endif
return 0;
}
+5
View File
@@ -775,6 +775,11 @@ ble_hs_init(void)
rc = ble_gattc_init();
SYSINIT_PANIC_ASSERT(rc == 0);
#if MYNEWT_VAL(BLE_GATT_CACHING)
rc = ble_gattc_cache_conn_init();
SYSINIT_PANIC_ASSERT(rc == 0);
#endif
rc = ble_gatts_init();
SYSINIT_PANIC_ASSERT(rc == 0);
#endif
+3
View File
@@ -44,6 +44,9 @@
#include "host/ble_hs.h"
#include "nimble/nimble_opt.h"
#include "stats/stats.h"
#if MYNEWT_VAL(BLE_GATT_CACHING)
#include "ble_gattc_cache_priv.h"
#endif
#ifdef __cplusplus
extern "C" {
#endif
+2 -2
View File
@@ -260,7 +260,7 @@ ble_sm_alg_log_buf(const char *name, const uint8_t *buf, int len)
*/
#if MYNEWT_VAL(BLE_CRYPTO_STACK_MBEDTLS)
static int
int
ble_sm_alg_aes_cmac(const uint8_t *key, const uint8_t *in, size_t len,
uint8_t *out)
{
@@ -298,7 +298,7 @@ exit:
}
#else
static int
int
ble_sm_alg_aes_cmac(const uint8_t *key, const uint8_t *in, size_t len,
uint8_t *out)
{
+2
View File
@@ -424,6 +424,8 @@ int ble_sm_init(void);
struct ble_l2cap_chan *ble_sm_create_chan(uint16_t handle);
void *ble_sm_cmd_get(uint8_t opcode, size_t len, struct os_mbuf **txom);
int ble_sm_tx(uint16_t conn_handle, struct os_mbuf *txom);
int ble_sm_alg_aes_cmac(const uint8_t *key, const uint8_t *in, size_t len, uint8_t *out);
#ifdef __cplusplus
}
@@ -0,0 +1,47 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#ifndef _STORAGE_PORT_H
#define _STORAGE_PORT_H
#include <stdio.h>
typedef enum {
READONLY,
READWRITE
} open_mode_t;
typedef uint32_t cache_handle_t;
typedef int (*open_cache)(const char *namespace_name, open_mode_t open_mode, cache_handle_t *out_handle);
typedef void (*close_cache)(cache_handle_t handle);
typedef int (*erase_all_cache)(cache_handle_t handle);
typedef int (*write_cache)(cache_handle_t handle, const char *key, const void* value, size_t length);
typedef int (*read_cache)(cache_handle_t handle, const char *key, void* out_value, size_t *length);
struct cache_fn_mapping {
open_cache open;
close_cache close;
erase_all_cache erase_all;
write_cache write;
read_cache read;
};
struct cache_fn_mapping link_storage_fn(void *storage_cb);
#endif