Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -728,6 +728,15 @@ config BLUETOOTH_GATTS_MAX_CONNECTIONS
config BLUETOOTH_GATTS_MAX_ATTRIBUTE_NUM
int "GATT Server max number of attributes contained in a table"
default 10

config BLUETOOTH_GATTS_CACHE_SUPPORT
bool "Enable GATT Server Cache Support"
default y
depends on BLUETOOTH_BLE_SUPPORT
help
Enable internal GATT attribute table hash comparison.
On reconnect, trusted devices may receive Service Changed indications
if attribute changes are detected.
endif # BLUETOOTH_GATT_SERVER

menuconfig BLUETOOTH_SPP
Expand Down
10 changes: 10 additions & 0 deletions service/common/bluetooth_define.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
#include "bt_uuid.h"
// #define BLE_MAX_ADV_NUM 8

#define BT_GATT_HASH_LEN 16

#define SMP_KEYS_MAX_SIZE 80
#define BT_COMMON_KEY_LENGTH 16

Expand Down Expand Up @@ -91,6 +93,13 @@ typedef struct {
uint8_t local_csrk[16];
} __attribute__((aligned(4))) remote_device_le_properties_v5_0_3_t;

typedef struct {
bt_address_t addr;
ble_addr_type_t addr_type;
// only can add member after "addr_type" if needed, see function bt_storage_save_le_remote_device for reasons.
uint8_t hash[BT_GATT_HASH_LEN];
} __attribute__((aligned(4))) remote_device_gatt_properties_v5_0_3_t;

typedef struct {
char name[BT_LOC_NAME_MAX_LEN + 1];
uint8_t pad[3];
Expand All @@ -103,6 +112,7 @@ typedef struct {

typedef remote_device_properties_v5_0_3_t remote_device_properties_t;
typedef remote_device_le_properties_v5_0_3_t remote_device_le_properties_t;
typedef remote_device_gatt_properties_v5_0_3_t remote_device_gatt_properties_t;
typedef adapter_storage_v5_0_3_t adapter_storage_t;

#endif /* __BLUETOOTH_DEFINE_H_ */
11 changes: 11 additions & 0 deletions service/common/storage.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
#define BT_KEY_BLEBOND "BleBonded"
#define BT_KEY_BLEWHITELIST "WhiteList"
#define BT_KEY_BLERESOLVINGLIST "ResolvingList"
#define BT_KEY_BLEGATTHASH "BleGattDBHash"

typedef struct {
uint16_t items;
Expand Down Expand Up @@ -146,6 +147,11 @@ static int bt_storage_save_remote_device(const char* key, void* value, uint16_t
return ret;
}

int bt_storage_save_gatt_cache_device(remote_device_gatt_properties_t* remote, uint16_t size)
{
return bt_storage_save_remote_device(BT_KEY_BLEGATTHASH, remote, sizeof(*remote), size);
}

int bt_storage_save_bonded_device(remote_device_properties_t* remote, uint16_t size)
{
return bt_storage_save_remote_device(BT_KEY_BTBOND, remote, sizeof(*remote), size);
Expand All @@ -161,6 +167,11 @@ int bt_storage_save_le_bonded_device(remote_device_le_properties_t* remote, uint
return bt_storage_save_remote_device(BT_KEY_BLEBOND, remote, sizeof(*remote), size);
}

int bt_storage_load_gatt_cache_device(load_storage_callback_t cb)
{
return storage_get_key(BT_KEY_BLEGATTHASH, NULL, NULL, (void*)cb);
}

int bt_storage_load_bonded_device(load_storage_callback_t cb)
{
return storage_get_key(BT_KEY_BTBOND, NULL, NULL, (void*)cb);
Expand Down
3 changes: 3 additions & 0 deletions service/common/storage.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,11 @@ int bt_storage_load_adapter_info(adapter_storage_t* adapter);
int bt_storage_save_bonded_device(remote_device_properties_t* remote, uint16_t size);
int bt_storage_save_whitelist(remote_device_le_properties_t* remote, uint16_t size);
int bt_storage_save_le_bonded_device(remote_device_le_properties_t* remote, uint16_t size);
int bt_storage_save_gatt_cache_device(remote_device_gatt_properties_t* remote, uint16_t size);
int bt_storage_load_bonded_device(load_storage_callback_t cb);
int bt_storage_load_whitelist_device(load_storage_callback_t cb);
int bt_storage_load_le_bonded_device(load_storage_callback_t cb);
int bt_storage_load_gatt_cache_device(load_storage_callback_t cb);

#ifdef CONFIG_BLUETOOTH_STORAGE_PROPERTY_SUPPORT
#define GEN_PROP_KEY(buf, key, address, len) snprintf((buf), (len), "%s%02X:%02X:%02X:%02X:%02X:%02X", \
Expand All @@ -57,6 +59,7 @@ int bt_storage_load_le_bonded_device(load_storage_callback_t cb);
#define BT_KVDB_BTBOND "persist.bluetooth.btbonded."
#define BT_KVDB_BLEBOND "persist.bluetooth.blebonded."
#define BT_KVDB_BLEWHITELIST "persist.bluetooth.whitelist."
#define BT_KVDB_BLEGATTDBHASH "persist.bluetooth.blegattDBhash."

int bt_storage_properties_destory(void);
void bt_storage_delete(char* key, uint16_t items, char* prop_name);
Expand Down
111 changes: 111 additions & 0 deletions service/common/storage_property.c
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,44 @@ static int bt_storage_save_le_remote_device(const char* key, void* value, uint16
return 0;
}

/*BT_KVDB_BLEGATTDBHASH*/
static int bt_storage_save_gatt_cache_remote_device(const char* key, void* value, uint16_t value_size, uint16_t items)
{
size_t prop_vlen;
char* prop_name;
remote_device_gatt_properties_t* data;
bt_address_t* addr;
int i;
int ret;

if (!key || !value)
return 0;

prop_name = (char*)malloc(PROP_NAME_MAX);
if (!prop_name) {
BT_LOGE("property_name malloc failed!");
return -ENOMEM;
}
data = (remote_device_gatt_properties_t*)value;
prop_vlen = value_size - offsetof(remote_device_gatt_properties_t, addr_type);
for (i = 0; i < items; i++) {
addr = &data->addr;
GEN_PROP_KEY(prop_name, key, addr, PROP_NAME_MAX);
/**
* Note: It should be ensured that "addr" is the first member of the struct remote_device_gatt_properties_t
* and "addr_type" is the second member.
* */
ret = storage_set_key(prop_name, &data->addr_type, prop_vlen);
if (ret < 0) {
free(prop_name);
return ret;
}
data++;
}
free(prop_name);
return 0;
}

static void callback_bt_count(const char* name, const char* value, void* count_u16)
{
if (!strncmp(name, BT_KVDB_BTBOND, strlen(BT_KVDB_BTBOND))) {
Expand All @@ -309,6 +347,13 @@ static void callback_le_count(const char* name, const char* value, void* count_u
}
}

static void callback_gatthash_count(const char* name, const char* value, void* count_u16)
{
if (!strncmp(name, BT_KVDB_BLEGATTDBHASH, strlen(BT_KVDB_BLEGATTDBHASH))) {
(*(uint16_t*)count_u16)++;
}
}

static void callback_whitelist_count(const char* name, const char* value, void* count_u16)
{
if (!strncmp(name, BT_KVDB_BLEWHITELIST, strlen(BT_KVDB_BLEWHITELIST))) {
Expand Down Expand Up @@ -422,6 +467,34 @@ int bt_storage_save_whitelist(remote_device_le_properties_t* remote, uint16_t si
return ret;
}

int bt_storage_save_gatt_cache_device(remote_device_gatt_properties_t* remote, uint16_t size)
{
uint16_t items = 0;
char* prop_name;
int ret;

prop_name = (char*)malloc(PROP_NAME_MAX);
if (!prop_name) {
BT_LOGE("property_name malloc failed!");
return -ENOMEM;
}

/* remove all BLE gatt cache device property before save new property*/
property_list(callback_gatthash_count, &items);
bt_storage_delete(BT_KVDB_BLEGATTDBHASH, items, prop_name);

ret = bt_storage_save_gatt_cache_remote_device(BT_KVDB_BLEGATTDBHASH, remote, sizeof(remote_device_gatt_properties_t), size);
if (ret < 0) {
BT_LOGE("save BLE gatt cache device failed!");
items = 0;
property_list(callback_gatthash_count, &items);
bt_storage_delete(BT_KVDB_BLEGATTDBHASH, items, prop_name);
}

free(prop_name);
return ret;
}

int bt_storage_save_le_bonded_device(remote_device_le_properties_t* remote, uint16_t size)
{
uint16_t items = 0;
Expand Down Expand Up @@ -482,6 +555,38 @@ int bt_storage_load_bonded_device(load_storage_callback_t cb)
return 0;
}

int bt_storage_load_gatt_cache_device(load_storage_callback_t cb)
{
uint16_t items;
bt_property_value_t* prop_value;
uint32_t total_length;
int ret;

items = 0;
ret = property_list(callback_gatthash_count, &items);
if (ret < 0) {
BT_LOGE("property_list failed!");
return ret;
}

total_length = items * sizeof(remote_device_gatt_properties_t);
prop_value = malloc(sizeof(bt_property_value_t) + total_length);
if (!prop_value) {
BT_LOGE("property malloc failed!");
return -ENOMEM;
}

prop_value->key = BT_KVDB_BLEGATTDBHASH;
prop_value->items = items;
prop_value->offset = 0;
prop_value->value_length = total_length;

storage_get_key(BT_KVDB_BLEGATTDBHASH, (void*)prop_value, sizeof(remote_device_gatt_properties_t), (void*)cb);
free(prop_value);

return 0;
}

int bt_storage_load_whitelist_device(load_storage_callback_t cb)
{
uint16_t items;
Expand Down Expand Up @@ -567,6 +672,11 @@ int bt_storage_properties_destory(void)
property_list(callback_whitelist_count, &items);
bt_storage_delete(BT_KVDB_BLEWHITELIST, items, prop_name);

/* remove all GATT cache device property */
items = 0;
property_list(callback_gatthash_count, &items);
bt_storage_delete(BT_KVDB_BLEGATTDBHASH, items, prop_name);

/* remove all BREDR bond device property */
items = 0;
property_list(callback_bt_count, &items);
Expand All @@ -580,6 +690,7 @@ int bt_storage_properties_destory(void)
ret |= property_delete(BT_KVDB_ADAPTERINFO_IOCAP);
ret |= property_delete(BT_KVDB_ADAPTERINFO_SCAN);
ret |= property_delete(BT_KVDB_ADAPTERINFO_BOND);
ret |= property_delete(BT_KVDB_ADAPTERINFO_IRK);
if (ret) {
BT_LOGE("property_delete failed!");
return ret;
Expand Down
95 changes: 94 additions & 1 deletion service/profiles/gatt/gatts_service.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include <stdint.h>
#include <sys/types.h>

#include "adapter_internel.h"
#include "bt_list.h"
#include "bt_profile.h"
#include "gatts_event.h"
Expand Down Expand Up @@ -236,6 +237,50 @@ static gatts_op_t* gatts_pendops_execute_out(gatts_manager_t* manager, gatts_req
return NULL;
}

#ifdef CONFIG_BLUETOOTH_GATTS_CACHE_SUPPORT
static void gatts_process_database_hash_evt(struct gatts_db_hash_evt_param* evt)
{
bt_status_t status;
char addr_str[BT_ADDR_STR_LENGTH] = { 0 };
uint8_t stored_hash[BT_GATT_HASH_LEN] = { 0 };

if (!evt) {
BT_LOGE("%s, invalid param", __func__);
return;
}

bt_addr_ba2str(&evt->addr, addr_str);
BT_LOGD("GATTS-DB-HASH-EVENT from:%s, force_update:%d, hash:"
"%02X%02X%02X%02X%02X%02X%02X%02X"
"%02X%02X%02X%02X%02X%02X%02X%02X",
addr_str, evt->force_update,
evt->hash[0], evt->hash[1], evt->hash[2], evt->hash[3],
evt->hash[4], evt->hash[5], evt->hash[6], evt->hash[7],
evt->hash[8], evt->hash[9], evt->hash[10], evt->hash[11],
evt->hash[12], evt->hash[13], evt->hash[14], evt->hash[15]);

status = adapter_get_device_gatt_hash(&evt->addr, evt->addr_type, stored_hash);
if (status != BT_STATUS_SUCCESS) {
BT_LOGD("No bonded, skip.");
return;
}

if (!memcmp(stored_hash, evt->hash, sizeof(stored_hash))) {
BT_LOGD("DB Hash unchanged, no action.");
return;
}

if (evt->force_update) {
BT_LOGI("Force update");
} else {
BT_LOGI("Hash mismatch, trigger Service Changed: %s", addr_str);
bt_sal_gatt_server_change_indicate(PRIMARY_ADAPTER, 0x0001, 0xFFFF);
}

adapter_set_device_gatt_hash((bt_address_t*)&evt->addr, evt->addr_type, evt->hash);
}
#endif

static void gatts_process_message(void* data)
{
gatts_service_t* service;
Expand Down Expand Up @@ -265,6 +310,10 @@ static void gatts_process_message(void* data)
profile_connection_state_t connect_state = msg->param.connect_change.state;
BT_ADDR_LOG("GATTS-CONNECTION-STATE-EVENT from:%s, state:%d", &msg->param.connect_change.addr, connect_state);
if (connect_state == PROFILE_STATE_CONNECTED) {
#ifdef CONFIG_BLUETOOTH_GATTS_CACHE_SUPPORT
/* Always fetch latest db hash when gatt connected */
bt_sal_gatt_server_get_database_hash(PRIMARY_ADAPTER, &msg->param.connect_change.addr, false);
#endif
GATTS_CALLBACK_FOREACH(g_gatts_manager.services, gatts_service_t, on_connected, &msg->param.connect_change.addr);
} else if (connect_state == PROFILE_STATE_DISCONNECTED) {
GATTS_CALLBACK_FOREACH(g_gatts_manager.services, gatts_service_t, on_disconnected, &msg->param.connect_change.addr);
Expand Down Expand Up @@ -341,6 +390,12 @@ static void gatts_process_message(void* data)
GATTS_CALLBACK_FOREACH(g_gatts_manager.services, gatts_service_t, on_conn_param_changed, &msg->param.conn_param.addr,
msg->param.conn_param.interval, msg->param.conn_param.latency, msg->param.conn_param.timeout);
break;
#ifdef CONFIG_BLUETOOTH_GATTS_CACHE_SUPPORT
case GATTS_EVENT_DB_HASH_AVAILABLE:
gatts_process_database_hash_evt(&msg->param.db_hash);
break;
#endif

default: {

} break;
Expand Down Expand Up @@ -428,6 +483,32 @@ static bt_status_t if_gatts_shutdown(profile_on_shutdown_t cb)
return BT_STATUS_SUCCESS;
}

static void if_gatts_process_msg(profile_msg_t* msg)
{
if (!msg) {
return;
}

switch (msg->event) {
#ifdef CONFIG_BLUETOOTH_GATTS_CACHE_SUPPORT
case PROFILE_EVT_GATTS_REQUEST_DB_HASH: {
bt_address_t* addr = (bt_address_t*)msg->data.data;
if (!addr) {
BT_LOGE("received null address");
break;
}

BT_ADDR_LOG("GATTS-DB-HASH-REQUEST to:%s, force_update:%d", addr, msg->data.valuebool);
bt_sal_gatt_server_get_database_hash(PRIMARY_ADAPTER, addr, msg->data.valuebool);
break;
}
#endif

default:
break;
}
}

static void if_gatts_cleanup(void)
{
g_gatts_manager.started = false;
Expand Down Expand Up @@ -832,6 +913,18 @@ void if_gatts_on_notification_sent(bt_address_t* addr, uint16_t element_id, gatt
gatts_send_message(msg);
}

#ifdef CONFIG_BLUETOOTH_GATTS_CACHE_SUPPORT
void if_gatts_on_database_hash(bt_address_t* addr, ble_addr_type_t addr_type, const uint8_t* hash, bool force_update)
{
gatts_msg_t* msg = gatts_msg_new(GATTS_EVENT_DB_HASH_AVAILABLE, 0);
memcpy(&msg->param.db_hash.addr, addr, sizeof(bt_address_t));
memcpy(msg->param.db_hash.hash, hash, BT_GATT_HASH_LEN);
msg->param.db_hash.addr_type = addr_type;
msg->param.db_hash.force_update = force_update;
gatts_send_message(msg);
}
#endif

void if_gatts_on_phy_read(bt_address_t* addr, ble_phy_type_t tx_phy, ble_phy_type_t rx_phy)
{
gatts_msg_t* msg = gatts_msg_new(GATTS_EVENT_PHY_READ, 0);
Expand Down Expand Up @@ -880,7 +973,7 @@ static const profile_service_t gatts_service = {
.init = if_gatts_init,
.startup = if_gatts_startup,
.shutdown = if_gatts_shutdown,
.process_msg = NULL,
.process_msg = if_gatts_process_msg,
.get_state = if_gatts_get_state,
.get_profile_interface = get_gatts_profile_interface,
.cleanup = if_gatts_cleanup,
Expand Down
Loading
Loading