From a51986616ea79260aeaeb6145affe8906fd9d334 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Delawarde?= Date: Tue, 5 Nov 2019 08:20:07 +0100 Subject: [PATCH] bluetooth: host: add ability to load CCC settings on demand MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commits adds a BT_SETTINGS_CCC_LAZY_LOADING option to allow for CCC settings to be loaded on demand when a peer device connects in order to reduce memory usage. Signed-off-by: François Delawarde --- include/bluetooth/gatt.h | 6 ++++- subsys/bluetooth/host/Kconfig | 9 +++++++ subsys/bluetooth/host/gatt.c | 45 +++++++++++++++++++++++++++++++++++ 3 files changed, 59 insertions(+), 1 deletion(-) diff --git a/include/bluetooth/gatt.h b/include/bluetooth/gatt.h index 1c6fbe25bc6..13cf4baa610 100644 --- a/include/bluetooth/gatt.h +++ b/include/bluetooth/gatt.h @@ -551,7 +551,11 @@ ssize_t bt_gatt_attr_read_chrc(struct bt_conn *conn, .properties = _props, })), \ BT_GATT_ATTRIBUTE(_uuid, _perm, _read, _write, _value) -#define BT_GATT_CCC_MAX (CONFIG_BT_MAX_PAIRED + CONFIG_BT_MAX_CONN) +#if IS_ENABLED(CONFIG_BT_SETTINGS_CCC_LAZY_LOADING) + #define BT_GATT_CCC_MAX (CONFIG_BT_MAX_CONN) +#else + #define BT_GATT_CCC_MAX (CONFIG_BT_MAX_PAIRED + CONFIG_BT_MAX_CONN) +#endif /** @brief GATT CCC configuration entry. * @param id Local identity, BT_ID_DEFAULT in most cases. diff --git a/subsys/bluetooth/host/Kconfig b/subsys/bluetooth/host/Kconfig index b2484bdc317..bb4440b4df4 100644 --- a/subsys/bluetooth/host/Kconfig +++ b/subsys/bluetooth/host/Kconfig @@ -173,6 +173,15 @@ config BT_SETTINGS instead of each subsystem doing it independently. if BT_SETTINGS +config BT_SETTINGS_CCC_LAZY_LOADING + bool "Load CCC values from settings when peer connects" + default y + help + Load Client Configuration Characteristic setting right after a bonded + device connects. + Disabling this option will increase memory usage as CCC values for all + bonded devices will be loaded when calling settings_load. + config BT_SETTINGS_CCC_STORE_ON_WRITE bool "Store CCC value immediately after it has been written" help diff --git a/subsys/bluetooth/host/gatt.c b/subsys/bluetooth/host/gatt.c index a6b900d32d0..28ea0358296 100644 --- a/subsys/bluetooth/host/gatt.c +++ b/subsys/bluetooth/host/gatt.c @@ -3585,6 +3585,11 @@ static void add_subscriptions(struct bt_conn *conn) #endif /* CONFIG_BT_GATT_CLIENT */ +#if IS_ENABLED(CONFIG_BT_SETTINGS_CCC_LAZY_LOADING) +static int ccc_set_direct(const char *key, size_t len, settings_read_cb read_cb, + void *cb_arg, void *param); +#endif /* CONFIG_BT_SETTINGS_CCC_LAZY_LOADING */ + void bt_gatt_connected(struct bt_conn *conn) { struct conn_data data; @@ -3594,6 +3599,26 @@ void bt_gatt_connected(struct bt_conn *conn) data.conn = conn; data.sec = BT_SECURITY_L1; +#if IS_ENABLED(CONFIG_BT_SETTINGS_CCC_LAZY_LOADING) + /* Load CCC settings from backend if bonded */ + if (bt_addr_le_is_bonded(conn->id, &conn->le.dst)) { + char key[BT_SETTINGS_KEY_MAX]; + + if (conn->id) { + char id_str[4]; + + u8_to_dec(id_str, sizeof(id_str), conn->id); + bt_settings_encode_key(key, sizeof(key), "ccc", + &conn->le.dst, id_str); + } else { + bt_settings_encode_key(key, sizeof(key), "ccc", + &conn->le.dst, NULL); + } + + settings_load_subtree_direct(key, ccc_set_direct, (void *)key); + } +#endif /* CONFIG_BT_SETTINGS_CCC_LAZY_LOADING */ + bt_gatt_foreach_attr(0x0001, 0xffff, update_ccc, &data); /* BLUETOOTH CORE SPECIFICATION Version 5.1 | Vol 3, Part C page 2192: @@ -4124,7 +4149,27 @@ static int ccc_set(const char *name, size_t len_rd, settings_read_cb read_cb, return 0; } +#if IS_ENABLED(CONFIG_BT_SETTINGS_CCC_LAZY_LOADING) +static int ccc_set_direct(const char *key, size_t len, settings_read_cb read_cb, + void *cb_arg, void *param) +{ + const char *name; + + BT_DBG("key: %s", log_strdup((const char *)param)); + + /* Only "bt/ccc" settings should ever come here */ + if (!settings_name_steq((const char *)param, "bt/ccc", &name)) { + BT_ERR("Invalid key"); + return -EINVAL; + } + + return ccc_set(name, len, read_cb, cb_arg); +} +#else +/* Only register the ccc_set settings handler when not loading on-demand */ SETTINGS_STATIC_HANDLER_DEFINE(bt_ccc, "bt/ccc", NULL, ccc_set, NULL, NULL); +#endif /* CONFIG_BT_SETTINGS_CCC_LAZY_LOADING */ + #if defined(CONFIG_BT_GATT_SERVICE_CHANGED) static int sc_set(const char *name, size_t len_rd, settings_read_cb read_cb,