From c5f522fd20e51740d282aeeb2e04428abfe02df6 Mon Sep 17 00:00:00 2001 From: Pavel Vasilyev Date: Tue, 11 Feb 2025 21:41:47 +0100 Subject: [PATCH 01/20] [nrf fromtree] bluetooth: host: smp: fix deadlock when public key generation fails When `bt_le_oob_get_local` or `bt_le_ext_adv_oob_get_local` is called and SMP is enabled, `bt_smp_le_oob_generate_sc_data` is called to generate a Random Number and a Confirmation Value needed for OOB data. These values are based on the device's public key. The public key is generated only once when `bt_smp_init` is called. If public key generation fails, the callback passed to `bt_pub_key_get` is called with `pkey` set to NULL. The `bt_smp_pkey_ready` callback gets called, but it doesn't release the `sc_local_pkey_ready` semaphore thus leaving `bt_smp_le_oob_generate_sc_data` wait for semaphore with `K_FOREVER`. This commit replaces the semaphore with a conditional variable and requests a public key again if the key is NULL thus solving 2 issues: - handling the case where the callback was triggered notifying about the completion of the public key request, but the key was not generated, - handling the case where multiple threads trying to acquire the same sempahore. The timeout is used instead of K_FOREVER to avoid cases when callback has never been triggered. Signed-off-by: Pavel Vasilyev (cherry picked from commit 9757ffa5fa46612737bc4814d373443ba0d043a1) --- subsys/bluetooth/host/smp.c | 73 ++++++++++++++++++++++++++++++++----- 1 file changed, 64 insertions(+), 9 deletions(-) diff --git a/subsys/bluetooth/host/smp.c b/subsys/bluetooth/host/smp.c index db936b28fdf..d439024d5c5 100644 --- a/subsys/bluetooth/host/smp.c +++ b/subsys/bluetooth/host/smp.c @@ -284,7 +284,19 @@ static bool sc_oobd_present; static bool legacy_oobd_present; static bool sc_supported; static const uint8_t *sc_public_key; -static K_SEM_DEFINE(sc_local_pkey_ready, 0, 1); + +static void bt_smp_pkey_ready(const uint8_t *pkey); +static struct { + struct k_mutex lock; + struct k_condvar condvar; + struct bt_pub_key_cb cb; +} pub_key_gen = { + .lock = Z_MUTEX_INITIALIZER(pub_key_gen.lock), + .condvar = Z_CONDVAR_INITIALIZER(pub_key_gen.condvar), + .cb = { + .func = bt_smp_pkey_ready, + }, +}; /* Pointer to internal data is used to mark that callbacks of given SMP channel are not initialized. * Value of NULL represents no authentication capabilities and cannot be used for that purpose. @@ -4627,6 +4639,21 @@ static int bt_smp_recv(struct bt_l2cap_chan *chan, struct net_buf *buf) return 0; } +static void pub_key_ready_notify(void) +{ + int err; + + ARG_UNUSED(err); + + err = k_mutex_lock(&pub_key_gen.lock, K_FOREVER); + __ASSERT_NO_MSG(err == 0); + + (void)k_condvar_broadcast(&pub_key_gen.condvar); + + err = k_mutex_unlock(&pub_key_gen.lock); + __ASSERT_NO_MSG(err == 0); +} + static void bt_smp_pkey_ready(const uint8_t *pkey) { int i; @@ -4635,13 +4662,13 @@ static void bt_smp_pkey_ready(const uint8_t *pkey) sc_public_key = pkey; + pub_key_ready_notify(); + if (!pkey) { LOG_WRN("Public key not available"); return; } - k_sem_give(&sc_local_pkey_ready); - for (i = 0; i < ARRAY_SIZE(bt_smp_pool); i++) { struct bt_smp *smp = &bt_smp_pool[i]; uint8_t err; @@ -5663,10 +5690,42 @@ int bt_smp_le_oob_generate_sc_data(struct bt_le_oob_sc_data *le_sc_oob) } if (!sc_public_key) { - err = k_sem_take(&sc_local_pkey_ready, K_FOREVER); + /* Public key request has not been finished yet, or finished, but generation failed. + * Retrying. + */ + err = k_mutex_lock(&pub_key_gen.lock, K_FOREVER); + __ASSERT_NO_MSG(err == 0); + + err = bt_pub_key_gen(&pub_key_gen.cb); + if (err && err != -EALREADY) { + LOG_WRN("Public key re-generation request failed (%d)", err); + + int mutex_err; + + mutex_err = k_mutex_unlock(&pub_key_gen.lock); + __ASSERT_NO_MSG(mutex_err == 0); + + return err; + } + + /* 30 seconds is an arbitrary number. Increase if fails earlier on certain + * platforms. + */ + err = k_condvar_wait(&pub_key_gen.condvar, + &pub_key_gen.lock, + K_SECONDS(30)); if (err) { + LOG_WRN("Public key generation timeout"); return err; } + + err = k_mutex_unlock(&pub_key_gen.lock); + __ASSERT_NO_MSG(err == 0); + + /* Public key has been re-requested but generation failed. */ + if (!sc_public_key) { + return -EAGAIN; + } } if (IS_ENABLED(CONFIG_BT_OOB_DATA_FIXED)) { @@ -6077,10 +6136,6 @@ BT_L2CAP_BR_CHANNEL_DEFINE(smp_br_fixed_chan, BT_L2CAP_CID_BR_SMP, int bt_smp_init(void) { - static struct bt_pub_key_cb pub_key_cb = { - .func = bt_smp_pkey_ready, - }; - sc_supported = le_sc_supported(); if (IS_ENABLED(CONFIG_BT_SMP_SC_PAIR_ONLY) && !sc_supported) { LOG_ERR("SC Pair Only Mode selected but LE SC not supported"); @@ -6095,7 +6150,7 @@ int bt_smp_init(void) LOG_DBG("LE SC %s", sc_supported ? "enabled" : "disabled"); if (!IS_ENABLED(CONFIG_BT_SMP_OOB_LEGACY_PAIR_ONLY)) { - bt_pub_key_gen(&pub_key_cb); + bt_pub_key_gen(&pub_key_gen.cb); } return smp_self_test(); From 93101a6eea206980cf5c187f93e668daf892f2fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Cab=C3=A9?= Date: Mon, 17 Feb 2025 18:00:30 +0100 Subject: [PATCH 02/20] [nrf fromtree] Bluetooth: Host: drop deprecated BT_LE_SCAN_OPT_FILTER_WHITELIST macro MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Macro has been deprecated since 2.7 LTS(!) and is using non-inclusive terminology. Drop it. Signed-off-by: Benjamin Cabé (cherry picked from commit 110c49fc47b170d9e184f768799103c025578db2) --- include/zephyr/bluetooth/bluetooth.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/zephyr/bluetooth/bluetooth.h b/include/zephyr/bluetooth/bluetooth.h index d1618f98a3a..d724ba3b2f8 100644 --- a/include/zephyr/bluetooth/bluetooth.h +++ b/include/zephyr/bluetooth/bluetooth.h @@ -2169,8 +2169,6 @@ enum { BT_LE_SCAN_OPT_NO_1M = BIT(3), }; -#define BT_LE_SCAN_OPT_FILTER_WHITELIST __DEPRECATED_MACRO BT_LE_SCAN_OPT_FILTER_ACCEPT_LIST - enum { /** Scan without requesting additional information from advertisers. */ BT_LE_SCAN_TYPE_PASSIVE = 0x00, From d561d91c2d9525a7ccea4b961938905835a80482 Mon Sep 17 00:00:00 2001 From: Jens Rehhoff Thomsen Date: Tue, 18 Feb 2025 12:46:30 +0100 Subject: [PATCH 03/20] [nrf fromtree] Bluetooth: host: Fix bug in scan start When scanning is started on bt_bap_broadcast_assistant_scan_start then BAP_BA_FLAG_SCANNING flag for the broadcast assistant instance should not be cleared. Fixes #85937 Signed-off-by: Jens Rehhoff Thomsen (cherry picked from commit c44334374eac27c7f3ab99c5c67901b29708ac89) --- subsys/bluetooth/audio/bap_broadcast_assistant.c | 1 - 1 file changed, 1 deletion(-) diff --git a/subsys/bluetooth/audio/bap_broadcast_assistant.c b/subsys/bluetooth/audio/bap_broadcast_assistant.c index 4d38b9307fd..5c3973a57f1 100644 --- a/subsys/bluetooth/audio/bap_broadcast_assistant.c +++ b/subsys/bluetooth/audio/bap_broadcast_assistant.c @@ -1172,7 +1172,6 @@ int bt_bap_broadcast_assistant_scan_start(struct bt_conn *conn, bool start_scan) cp->opcode = BT_BAP_BASS_OP_SCAN_START; - atomic_clear_bit(inst->flags, BAP_BA_FLAG_SCANNING); err = bt_bap_broadcast_assistant_common_cp(conn, &att_buf); if (err != 0 && start_scan) { /* bt_bap_broadcast_assistant_common_cp clears the busy flag on error */ From 0e5d43b5c10516bac4865119f5e59864f2aadd93 Mon Sep 17 00:00:00 2001 From: Vinayak Kariappa Chettimada Date: Mon, 13 Jan 2025 15:34:05 +0100 Subject: [PATCH 04/20] [nrf fromtree] Bluetooth: Host: Remove nested allocation of HCI command buffer Remove nested allocation of HCI command buffer so that one less HCI command buffer is needed starting extended advertising with privacy enabled. Signed-off-by: Vinayak Kariappa Chettimada (cherry picked from commit cc1b53445c2766b173aed910c40db5776b49ad44) --- subsys/bluetooth/host/adv.c | 38 +++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/subsys/bluetooth/host/adv.c b/subsys/bluetooth/host/adv.c index d99144a420d..d2e0c255e12 100644 --- a/subsys/bluetooth/host/adv.c +++ b/subsys/bluetooth/host/adv.c @@ -1127,10 +1127,25 @@ static int le_ext_adv_param_set(struct bt_le_ext_adv *adv, uint16_t size; bool dir_adv = param->peer != NULL, scannable; struct net_buf *buf, *rsp; + uint8_t own_addr_type; int err; enum adv_name_type name_type; uint16_t props = 0; + adv->options = param->options; + + err = bt_id_set_adv_own_addr(adv, param->options, dir_adv, + &own_addr_type); + if (err) { + return err; + } + + if (dir_adv) { + bt_addr_le_copy(&adv->target_addr, param->peer); + } else { + bt_addr_le_copy(&adv->target_addr, BT_ADDR_LE_ANY); + } + if (IS_ENABLED(CONFIG_BT_EXT_ADV_CODING_SELECTION) && BT_FEAT_LE_ADV_CODING_SEL(bt_dev.le.features)) { opcode = BT_HCI_OP_LE_SET_EXT_ADV_PARAM_V2; @@ -1148,31 +1163,15 @@ static int le_ext_adv_param_set(struct bt_le_ext_adv *adv, cp = net_buf_add(buf, size); (void)memset(cp, 0, size); - adv->options = param->options; - - err = bt_id_set_adv_own_addr(adv, param->options, dir_adv, - &cp->own_addr_type); - if (err) { - net_buf_unref(buf); - return err; - } - - if (dir_adv) { - bt_addr_le_copy(&adv->target_addr, param->peer); - } else { - bt_addr_le_copy(&adv->target_addr, BT_ADDR_LE_ANY); - } - - name_type = get_adv_name_type_param(param); - cp->handle = adv->handle; sys_put_le24(param->interval_min, cp->prim_min_interval); sys_put_le24(param->interval_max, cp->prim_max_interval); cp->prim_channel_map = get_adv_channel_map(param->options); + cp->own_addr_type = own_addr_type; cp->filter_policy = get_filter_policy(param->options); cp->tx_power = BT_HCI_LE_ADV_TX_POWER_NO_PREF; - cp->prim_adv_phy = BT_HCI_LE_PHY_1M; + if ((param->options & BT_LE_ADV_OPT_EXT_ADV) && !(param->options & BT_LE_ADV_OPT_NO_2M)) { cp->sec_adv_phy = BT_HCI_LE_PHY_2M; @@ -1229,6 +1228,8 @@ static int le_ext_adv_param_set(struct bt_le_ext_adv *adv, } } + name_type = get_adv_name_type_param(param); + if ((param->options & BT_LE_ADV_OPT_SCANNABLE) || has_scan_data || (name_type == ADV_NAME_TYPE_SD)) { props |= BT_HCI_LE_ADV_PROP_SCAN; @@ -1250,6 +1251,7 @@ static int le_ext_adv_param_set(struct bt_le_ext_adv *adv, cp->sec_adv_max_skip = param->secondary_max_skip; cp->props = sys_cpu_to_le16(props); + err = bt_hci_cmd_send_sync(opcode, buf, &rsp); if (err) { return err; From 3e79c8a48b4313c28029dcdb1dfd39cbb99adf33 Mon Sep 17 00:00:00 2001 From: Kyra Lengfeld Date: Wed, 26 Feb 2025 14:01:00 +0100 Subject: [PATCH 05/20] [nrf fromtree] Bluetooth: Host: improve GATT documentation The gatt docs are very sparce, this commit adds imrpovements for the GATT server API part. Others will follow. Signed-off-by: Kyra Lengfeld (cherry picked from commit 775cc352361dcd01419e8689481d1d7f27d52e26) --- include/zephyr/bluetooth/gatt.h | 100 +++++++++++++++++++++++++------- 1 file changed, 80 insertions(+), 20 deletions(-) diff --git a/include/zephyr/bluetooth/gatt.h b/include/zephyr/bluetooth/gatt.h index 5a20771e725..12b5b284df9 100644 --- a/include/zephyr/bluetooth/gatt.h +++ b/include/zephyr/bluetooth/gatt.h @@ -573,14 +573,14 @@ void bt_gatt_cb_register(struct bt_gatt_cb *cb); * * @param cb Callback struct. * - * @return Zero on success or negative error code otherwise + * @return Zero on success or negative error code otherwise. */ int bt_gatt_authorization_cb_register(const struct bt_gatt_authorization_cb *cb); /** @brief Register GATT service. * - * Register GATT service. Applications can make use of - * macros such as ``BT_GATT_PRIMARY_SERVICE``, ``BT_GATT_CHARACTERISTIC``, + * To register a GATT service, applications can make use of macros such as + * ``BT_GATT_PRIMARY_SERVICE``, ``BT_GATT_CHARACTERISTIC``, * ``BT_GATT_DESCRIPTOR``, etc. * * When using @kconfig{CONFIG_BT_SETTINGS} then all services that should have @@ -621,6 +621,9 @@ int bt_gatt_service_unregister(struct bt_gatt_service *svc); */ bool bt_gatt_service_is_registered(const struct bt_gatt_service *svc); +/** @brief to be used as return values for @ref bt_gatt_attr_func_t and @ref bt_gatt_read_func_t + * type callbacks. + */ enum { BT_GATT_ITER_STOP = 0, BT_GATT_ITER_CONTINUE, @@ -645,7 +648,8 @@ typedef uint8_t (*bt_gatt_attr_func_t)(const struct bt_gatt_attr *attr, * Iterate attributes in the given range matching given UUID and/or data. * * @param start_handle Start handle. - * @param end_handle End handle. + * @param end_handle End handle. Often set to start_handle + attr_count or + * BT_ATT_LAST_ATTRIBUTE_HANDLE. * @param uuid UUID to match, passing NULL skips UUID matching. * @param attr_data Attribute data to match, passing NULL skips data matching. * @param num_matches Number matches, passing 0 makes it unlimited. @@ -892,6 +896,16 @@ ssize_t bt_gatt_attr_read_chrc(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, uint16_t len, uint16_t offset); +/** @brief Gatt Characterisitc Initialization Macro. + * + * Helper macro used within the @ref BT_GATT_CHARACTERISTIC macro in the GATT attribute declaration + * to set the attribute user data. + * + * @param _uuid Characteristic attribute uuid. + * @param _handle Characcteristic attribute handle at init. + * @param _props Characteristic attribute properties, + * a bitmap of ``BT_GATT_CHRC_*`` macros. + */ #define BT_GATT_CHRC_INIT(_uuid, _handle, _props) \ { \ .uuid = _uuid, \ @@ -924,6 +938,17 @@ ssize_t bt_gatt_attr_read_chrc(struct bt_conn *conn, })), \ BT_GATT_ATTRIBUTE(_uuid, _perm, _read, _write, _user_data) +/** + * @brief BT_GATT_CCC_MAX is defined depending on whether + * @kconfig{CONFIG_BT_SETTINGS_CCC_LAZY_LOADING} or @kconfig{CONFIG_BT_CONN} is set. + * + * @kconfig{CONFIG_BT_SETTINGS_CCC_LAZY_LOADING} will set BT_GATT_CCC_MAX to + * @kconfig{CONFIG_BT_MAX_CONN} + * @kconfig{CONFIG_BT_CONN} will set BT_GATT_CCC_MAX to @kconfig{CONFIG_BT_MAX_PAIRED} + + * @kconfig{CONFIG_BT_MAX_CONN} + * If neither are set, BT_GATT_CCC_MAX is 0. + * + */ #if defined(CONFIG_BT_SETTINGS_CCC_LAZY_LOADING) #define BT_GATT_CCC_MAX (CONFIG_BT_MAX_CONN) #elif defined(CONFIG_BT_CONN) @@ -932,13 +957,21 @@ ssize_t bt_gatt_attr_read_chrc(struct bt_conn *conn, #define BT_GATT_CCC_MAX 0 #endif -/** @brief GATT CCC configuration entry. */ +/** @brief GATT CCC configuration entry. + * + * bt_gatt_ccc_cfg is used within @ref bt_gatt_attr_read_ccc and @ref bt_gatt_attr_write_ccc to + * read and write the ccc configurations respectively. + * + */ struct bt_gatt_ccc_cfg { /** Local identity, BT_ID_DEFAULT in most cases. */ uint8_t id; /** Remote peer address. */ bt_addr_le_t peer; - /** Configuration value. */ + /** @brief Configuration value + * Value used to enable or disable notifications or indications for a specific + * characteristic. + */ uint16_t value; }; @@ -989,8 +1022,6 @@ struct _bt_gatt_ccc { * Read CCC attribute value from local database storing the result into buffer * after encoding it. * - * @note Only use this with attributes which user_data is a _bt_gatt_ccc. - * * @param conn Connection object. * @param attr Attribute to read. * @param buf Buffer to store the value read. @@ -1000,6 +1031,11 @@ struct _bt_gatt_ccc { * @return number of bytes read in case of success or negative values in * case of error. */ +/** @cond INTERNAL_HIDDEN + * @note Only use this with attributes which user_data is a _bt_gatt_ccc. + * _bt_gatt_ccc being the internal representation of CCC value. + */ + /** @endcond */ ssize_t bt_gatt_attr_read_ccc(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, uint16_t len, uint16_t offset); @@ -1008,8 +1044,6 @@ ssize_t bt_gatt_attr_read_ccc(struct bt_conn *conn, * * Write value in the buffer into CCC attribute. * - * @note Only use this with attributes which user_data is a _bt_gatt_ccc. - * * @param conn Connection object. * @param attr Attribute to read. * @param buf Buffer to store the value read. @@ -1020,6 +1054,11 @@ ssize_t bt_gatt_attr_read_ccc(struct bt_conn *conn, * @return number of bytes written in case of success or negative values in * case of error. */ +/** @cond INTERNAL_HIDDEN + * @note Only use this with attributes which user_data is a _bt_gatt_ccc. + * _bt_gatt_ccc being the internal representation of CCC value. + */ + /** @endcond */ ssize_t bt_gatt_attr_write_ccc(struct bt_conn *conn, const struct bt_gatt_attr *attr, const void *buf, uint16_t len, uint16_t offset, uint8_t flags); @@ -1139,7 +1178,7 @@ ssize_t bt_gatt_attr_read_cud(struct bt_conn *conn, * Read CPF attribute value from local database storing the result into buffer * after encoding it. * - * @note Only use this with attributes which user_data is a bt_gatt_pf. + * @note Only use this with attributes which user_data is a @ref bt_gatt_cpf. * * @param conn Connection object * @param attr Attribute to read @@ -1211,6 +1250,10 @@ ssize_t bt_gatt_attr_read_cpf(struct bt_conn *conn, */ typedef void (*bt_gatt_complete_func_t) (struct bt_conn *conn, void *user_data); +/** @brief GATT notification parameters + * + * See also @ref bt_gatt_notify_cb and @ref bt_gatt_notify_multiple, using this parameter. + */ struct bt_gatt_notify_params { /** @brief Notification Attribute UUID type * @@ -1232,7 +1275,8 @@ struct bt_gatt_notify_params { bt_gatt_complete_func_t func; /** Notification Value callback user data */ void *user_data; -#if defined(CONFIG_BT_EATT) +#if defined(CONFIG_BT_EATT) || defined(__DOXYGEN__) + /** Att channel options. */ enum bt_att_chan_opt chan_opt; #endif /* CONFIG_BT_EATT */ }; @@ -1406,10 +1450,22 @@ typedef void (*bt_gatt_indicate_func_t)(struct bt_conn *conn, struct bt_gatt_indicate_params *params, uint8_t err); +/** @typedef bt_gatt_indicate_params_destroy_t + * @brief Callback to destroy or clean up the GATT Indicate Value parameters. + * + * This callback function is invoked to clean up any resources associated with the + * `bt_gatt_indicate_params` structure once the GATT indication operation is completed. + * + * @param params Pointer to the GATT Indicate parameters structure to be cleaned up. + */ typedef void (*bt_gatt_indicate_params_destroy_t)( struct bt_gatt_indicate_params *params); -/** @brief GATT Indicate Value parameters */ +/** @brief GATT Indicate Value parameters + * + * See also @ref bt_gatt_indicate, using this parameter. + * + */ struct bt_gatt_indicate_params { /** @brief Indicate Attribute UUID type * @@ -1433,7 +1489,8 @@ struct bt_gatt_indicate_params { uint16_t len; /** Private reference counter */ uint8_t _ref; -#if defined(CONFIG_BT_EATT) +#if defined(CONFIG_BT_EATT) || defined(__DOXYGEN__) + /** Att channel options. */ enum bt_att_chan_opt chan_opt; #endif /* CONFIG_BT_EATT */ }; @@ -1466,10 +1523,9 @@ struct bt_gatt_indicate_params { int bt_gatt_indicate(struct bt_conn *conn, struct bt_gatt_indicate_params *params); - /** @brief Check if connection have subscribed to attribute * - * Check if connection has subscribed to attribute value change. + * Check if the connection has subscribed to an attribute value change. * * The attribute object can be the so called Characteristic Declaration, * which is usually declared with BT_GATT_CHARACTERISTIC followed @@ -1684,7 +1740,8 @@ struct bt_gatt_discover_params { /** Only for stack-internal use, used for automatic discovery. */ struct bt_gatt_subscribe_params *sub_params; #endif /* defined(CONFIG_BT_GATT_AUTO_DISCOVER_CCC) || defined(__DOXYGEN__) */ -#if defined(CONFIG_BT_EATT) +#if defined(CONFIG_BT_EATT) || defined(__DOXYGEN__) + /** Att channel options. */ enum bt_att_chan_opt chan_opt; #endif /* CONFIG_BT_EATT */ }; @@ -1791,7 +1848,8 @@ struct bt_gatt_read_params { const struct bt_uuid *uuid; } by_uuid; }; -#if defined(CONFIG_BT_EATT) +#if defined(CONFIG_BT_EATT) || defined(__DOXYGEN__) + /** Att channel options. */ enum bt_att_chan_opt chan_opt; #endif /* CONFIG_BT_EATT */ /** Internal */ @@ -1866,7 +1924,8 @@ struct bt_gatt_write_params { const void *data; /** Length of the data */ uint16_t length; -#if defined(CONFIG_BT_EATT) +#if defined(CONFIG_BT_EATT) || defined(__DOXYGEN__) + /** Att channel options. */ enum bt_att_chan_opt chan_opt; #endif /* CONFIG_BT_EATT */ }; @@ -2074,7 +2133,8 @@ struct bt_gatt_subscribe_params { ATOMIC_DEFINE(flags, BT_GATT_SUBSCRIBE_NUM_FLAGS); sys_snode_t node; -#if defined(CONFIG_BT_EATT) +#if defined(CONFIG_BT_EATT) || defined(__DOXYGEN__) + /** Att channel options. */ enum bt_att_chan_opt chan_opt; #endif /* CONFIG_BT_EATT */ }; From a75e2f12982f0ed7e7c3b89f57178405da2ddef8 Mon Sep 17 00:00:00 2001 From: Kyra Lengfeld Date: Thu, 27 Feb 2025 07:45:46 +0100 Subject: [PATCH 06/20] [nrf fromtree] Bluetooth: Host: Fix deadlock when failing to alloc on BT RX thread This commit alignes the timeout value for allocating buffers within att on the BT RX thread, making it consistent within att.c, see bt_att_req_alloc. We are inferring in many bt_gatt_* functions that if called from a BT RX thread (which is inherently the case if called from a callback when running a Bluetooth application), we don't block and instead return -ENOMEM when the ATT request queue is full, avoiding a deadlock. This promise is fulfilled within bt_att_req_alloc, where the timeout for allocation of the request slab is set to K_NO_WAIT if we are on the BT RX thread. Unfortunately, we break this promise in bt_att_chan_create_pdu, where the timeout for allocation of the att pool is still K_FOREVER and deadlocks can (and do) occur when too many requests are sent yet the pool is depleted. Note: Both req_slab and att_pool sizes are defined by CONFIG_BT_ATT_TX_COUNT. If applications start getting -ENOMEM with this change, they were at risk of such a deadlock, and may increase CONFIG_BT_ATT_TX_COUNT to allocate the att pool for their requests. Note: This possible deadlock has been flying under the radar, as att_pools are freed when the HCI driver has sent it to the controller (instead of when receiving the response, as it happens with req_slabs) and due to the att_pool and the req_slab being both sized by CONFIG_BT_ATT_TX_COUNT, and req_slab being allocated before and returning -ENOMEM already if there is no space, it takes a more specific situation to deplete the att_pool but not the req_slab pool at this point. Note: Ideally, we don't want functions to behave differently depending on which thread they are running, and while this commit makes it more consistent, it should be considered a workaround solution. Signed-off-by: Kyra Lengfeld (cherry picked from commit 6464ffa3f94eb9d9203b56518cf53b141b1feea5) --- subsys/bluetooth/host/att.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/subsys/bluetooth/host/att.c b/subsys/bluetooth/host/att.c index c3fd0a8a7cf..9d83ba688d9 100644 --- a/subsys/bluetooth/host/att.c +++ b/subsys/bluetooth/host/att.c @@ -721,7 +721,13 @@ static struct net_buf *bt_att_chan_create_pdu(struct bt_att_chan *chan, uint8_t timeout = BT_ATT_TIMEOUT; break; default: - if (k_current_get() == k_work_queue_thread_get(&k_sys_work_q)) { + k_tid_t current_thread = k_current_get(); + + if (current_thread == k_work_queue_thread_get(&k_sys_work_q)) { + /* No blocking in the sysqueue. */ + timeout = K_NO_WAIT; + } else if (current_thread == att_handle_rsp_thread) { + /* Blocking would cause deadlock. */ timeout = K_NO_WAIT; } else { timeout = K_FOREVER; From be4811d890826f3034c077dae2c9dc8bb7042e97 Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Tue, 14 Jan 2025 14:23:46 +0100 Subject: [PATCH 07/20] [nrf fromtree] Bluetooth: GATT: Change get_handle function of find_by_uuid bt_gatt_find_by_uuid used bt_gatt_attr_value_handle but that function only works to get the value handle of a characteristic declaration, i.e. if the UUID is not BT_UUID_GATT_CHRC then it would always return handle = 0. This meant that bt_gatt_find_by_uuid would always use handle = 0 as the starting handle for non-BT_UUID_GATT_CHRC attributes, instead of the handle of the provided attr. This was not an issue for any UUIDs that may only exist once on a GATT server, which is most UUIDs, but for UUIDs like the BT_UUID_TBS_* UUIDs that may be multiple instances of, it would always return the first attribute rather than the one starting from the provided start attr. This commit also ensures that we do not overflow the `end_handle` when adding 2 uint16_t values. Signed-off-by: Emil Gydesen (cherry picked from commit e4c5bb99b098ad8d4115da30ce8b9b785bd265da) --- include/zephyr/bluetooth/gatt.h | 3 ++- subsys/bluetooth/host/gatt.c | 21 ++++++++++++++----- .../host/gatt/ccc_store/src/peripheral.c | 7 ++----- .../host/security/ccc_update/src/peripheral.c | 8 ++----- 4 files changed, 22 insertions(+), 17 deletions(-) diff --git a/include/zephyr/bluetooth/gatt.h b/include/zephyr/bluetooth/gatt.h index 12b5b284df9..f9a0712546c 100644 --- a/include/zephyr/bluetooth/gatt.h +++ b/include/zephyr/bluetooth/gatt.h @@ -721,7 +721,8 @@ uint16_t bt_gatt_attr_get_handle(const struct bt_gatt_attr *attr); * * @param attr A Characteristic Attribute. * - * @note The ``user_data`` of the attribute must of type @ref bt_gatt_chrc. + * @note The ``user_data`` of the attribute must of type @ref bt_gatt_chrc and the ``uuid`` shall be + * BT_UUID_GATT_CHRC * * @return the handle of the corresponding Characteristic Value. The value will * be zero (the invalid handle) if @p attr was not a characteristic diff --git a/subsys/bluetooth/host/gatt.c b/subsys/bluetooth/host/gatt.c index 688512b74f8..fa8fb1c7bd6 100644 --- a/subsys/bluetooth/host/gatt.c +++ b/subsys/bluetooth/host/gatt.c @@ -7,6 +7,9 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include + +#include #include #include #include @@ -2859,12 +2862,20 @@ struct bt_gatt_attr *bt_gatt_find_by_uuid(const struct bt_gatt_attr *attr, const struct bt_uuid *uuid) { struct bt_gatt_attr *found = NULL; - uint16_t start_handle = bt_gatt_attr_value_handle(attr); - uint16_t end_handle = start_handle && attr_count ? - start_handle + attr_count : 0xffff; + uint16_t start_handle = bt_gatt_attr_get_handle(attr); + uint16_t end_handle = start_handle && attr_count + ? MIN(start_handle + attr_count, BT_ATT_LAST_ATTRIBUTE_HANDLE) + : BT_ATT_LAST_ATTRIBUTE_HANDLE; + + if (attr != NULL && start_handle == 0U) { + /* If start_handle is 0 then `attr` is not in our database, and should not be used + * as a starting point for the search + */ + LOG_DBG("Could not find handle of attr %p", attr); + return NULL; + } - bt_gatt_foreach_attr_type(start_handle, end_handle, uuid, NULL, 1, - find_next, &found); + bt_gatt_foreach_attr_type(start_handle, end_handle, uuid, NULL, 1, find_next, &found); return found; } diff --git a/tests/bsim/bluetooth/host/gatt/ccc_store/src/peripheral.c b/tests/bsim/bluetooth/host/gatt/ccc_store/src/peripheral.c index 0df6d2b7f9f..fe12cb3c0e2 100644 --- a/tests/bsim/bluetooth/host/gatt/ccc_store/src/peripheral.c +++ b/tests/bsim/bluetooth/host/gatt/ccc_store/src/peripheral.c @@ -230,11 +230,8 @@ static void check_ccc_handle(void) __ASSERT(actual_val_handle == VAL_HANDLE, "Please update the VAL_HANDLE define (actual_val_handle=%d)", actual_val_handle); - struct bt_gatt_attr attr = { - .uuid = BT_UUID_GATT_CHRC, - .user_data = &(struct bt_gatt_chrc){ .value_handle = actual_val_handle }}; - - struct bt_gatt_attr *ccc_attr = bt_gatt_find_by_uuid(&attr, 0, BT_UUID_GATT_CCC); + struct bt_gatt_attr *ccc_attr = + bt_gatt_find_by_uuid(service_notify_attr, 0, BT_UUID_GATT_CCC); uint16_t actual_ccc_handle = bt_gatt_attr_get_handle(ccc_attr); __ASSERT(actual_ccc_handle == CCC_HANDLE, diff --git a/tests/bsim/bluetooth/host/security/ccc_update/src/peripheral.c b/tests/bsim/bluetooth/host/security/ccc_update/src/peripheral.c index 10cb4210c22..0f686e2d87c 100644 --- a/tests/bsim/bluetooth/host/security/ccc_update/src/peripheral.c +++ b/tests/bsim/bluetooth/host/security/ccc_update/src/peripheral.c @@ -271,12 +271,8 @@ static void check_ccc_handle(void) struct bt_gatt_attr *service_notify_attr = bt_gatt_find_by_uuid(NULL, 0, ¬ify_characteristic_uuid.uuid); - struct bt_gatt_attr attr = { - .uuid = BT_UUID_GATT_CHRC, - .user_data = &(struct bt_gatt_chrc){ - .value_handle = bt_gatt_attr_get_handle(service_notify_attr)}}; - - struct bt_gatt_attr *ccc_attr = bt_gatt_find_by_uuid(&attr, 0, BT_UUID_GATT_CCC); + struct bt_gatt_attr *ccc_attr = + bt_gatt_find_by_uuid(service_notify_attr, 0, BT_UUID_GATT_CCC); uint16_t actual_ccc_handle = bt_gatt_attr_get_handle(ccc_attr); __ASSERT(actual_ccc_handle == CCC_HANDLE, From 55f05d8f58182e64af55e602baf3adbeb208d5eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5vard=20Reierstad?= Date: Fri, 28 Feb 2025 08:36:57 +0100 Subject: [PATCH 08/20] [nrf fromtree] Bluetooth: Host: Improve more GATT documentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds improvement to the GATT API documentation by providing examples of where (and how) certain structs are used, and adds specification references to the fields of bt_gatt_cpf to clarify their purpose. Signed-off-by: Håvard Reierstad (cherry picked from commit c7a19da8ca1abefa8eac41e704e7c678af0282a9) --- doc/connectivity/bluetooth/api/gatt.rst | 17 ++- include/zephyr/bluetooth/gatt.h | 143 ++++++++++++++++++------ 2 files changed, 117 insertions(+), 43 deletions(-) diff --git a/doc/connectivity/bluetooth/api/gatt.rst b/doc/connectivity/bluetooth/api/gatt.rst index bb4487f57dd..58920cdcb65 100644 --- a/doc/connectivity/bluetooth/api/gatt.rst +++ b/doc/connectivity/bluetooth/api/gatt.rst @@ -4,10 +4,18 @@ Generic Attribute Profile (GATT) ################################ -GATT layer manages the service database providing APIs for service registration -and attribute declaration. +The GATT layer manages the service database providing APIs for service +registration and attribute declaration. -Services can be registered using :c:func:`bt_gatt_service_register` API +The GATT Client initiates commands and requests towards the GATT Server, and can +receive responses, indications and notifications sent by the server. It is +enabled through the configuration option: +:kconfig:option:`CONFIG_BT_GATT_CLIENT` + +The GATT Server accepts incoming commands and requests from the GATT Client, and +sends responses, indications and notifications to the client. + +Services can be registered using the :c:func:`bt_gatt_service_register` API which takes the :c:struct:`bt_gatt_service` struct that provides the list of attributes the service contains. The helper macro :c:macro:`BT_GATT_SERVICE()` can be used to declare a service. @@ -61,9 +69,6 @@ pass a callback to be called when it is necessary to know the exact instant when the data has been transmitted over the air. Indications are supported by :c:func:`bt_gatt_indicate` API. -Client procedures can be enabled with the configuration option: -:kconfig:option:`CONFIG_BT_GATT_CLIENT` - Discover procedures can be initiated with the use of :c:func:`bt_gatt_discover` API which takes the :c:struct:`bt_gatt_discover_params` struct which describes the type of diff --git a/include/zephyr/bluetooth/gatt.h b/include/zephyr/bluetooth/gatt.h index f9a0712546c..9e4ec0db993 100644 --- a/include/zephyr/bluetooth/gatt.h +++ b/include/zephyr/bluetooth/gatt.h @@ -12,6 +12,9 @@ /** * @brief Generic Attribute Profile (GATT) + * @details The GATT layer manages the service database by providing APIs for + * service registration and attribute declaration. For more + * information, see @ref bt_gatt_client and @ref bt_gatt_server. * @defgroup bt_gatt Generic Attribute Profile (GATT) * @ingroup bluetooth * @{ @@ -222,9 +225,9 @@ typedef ssize_t (*bt_gatt_attr_write_func_t)(struct bt_conn *conn, * pass the pointer to GATT server APIs. */ struct bt_gatt_attr { - /** @brief Attribute Type, aka. "UUID" + /** @brief Attribute Type * - * The Attribute Type determines the interface that can + * The Attribute Type is a UUID which determines the interface that can * be expected from the read() and write() methods and * the possible permission configurations. * @@ -275,16 +278,13 @@ struct bt_gatt_attr { */ void *user_data; - /** @brief Attribute Handle or zero, maybe? + /** @brief Attribute Handle * - * The meaning of this field varies and is not specified here. - * Some APIs use this field as input/output. It does not always - * contain the Attribute Handle. + * The Attribute Handle is an index corresponding to a specific + * Attribute in the ATT database. * * @note Use bt_gatt_attr_get_handle() for attributes in the * local ATT database. - * - * @sa bt_gatt_discover_func_t about this field. */ uint16_t handle; @@ -294,8 +294,6 @@ struct bt_gatt_attr { * * The permissions are security requirements that must be * satisfied before calling read() or write(). - * - * @sa bt_gatt_discover_func_t about this field. */ uint16_t perm: 15; @@ -311,7 +309,12 @@ struct bt_gatt_attr { /** @endcond */ }; -/** @brief GATT Service structure */ +/** @brief Static GATT Service structure + * + * Allows the user the declare static GATT Services with the aim of reducing the + * used RAM. The @ref BT_GATT_SERVICE_DEFINE macro can be used to statically + * define and register a service. + */ struct bt_gatt_service_static { /** Service Attributes */ const struct bt_gatt_attr *attrs; @@ -319,31 +322,48 @@ struct bt_gatt_service_static { size_t attr_count; }; -/** @brief GATT Service structure */ +/** @brief GATT Service structure + * + * This structure is used to define GATT services which can be registered and + * unregistered at runtime. See @ref bt_gatt_service_register for when services + * should be registered. + */ struct bt_gatt_service { /** Service Attributes */ struct bt_gatt_attr *attrs; /** Service Attribute count */ size_t attr_count; - + /** @cond INTERNAL_HIDDEN + * Field used for list handling. + */ sys_snode_t node; + /** @endcond */ }; -/** @brief Service Attribute Value. */ +/** @brief Service Attribute Value. + * + * This is the data described by the Attribute Type and indexed by the + * Attribute Handle in the database. + */ struct bt_gatt_service_val { /** Service UUID. */ const struct bt_uuid *uuid; - /** Service end handle. */ + /** Handle of the last Attribute within the Service. */ uint16_t end_handle; }; -/** @brief Include Attribute Value. */ +/** @brief Include Attribute Value. + * + * This structure represents an included service attribute in the GATT + * server. An included service is a service that is referenced within another + * service, allowing for the reuse of common service definitions. + */ struct bt_gatt_include { /** Service UUID. */ const struct bt_uuid *uuid; - /** Service start handle. */ + /** Handle of the first attribute within the included service. */ uint16_t start_handle; - /** Service end handle. */ + /** Handle of the last attribute within the included service. */ uint16_t end_handle; }; @@ -360,7 +380,11 @@ struct bt_gatt_cb { */ void (*att_mtu_updated)(struct bt_conn *conn, uint16_t tx, uint16_t rx); + /** @cond INTERNAL_HIDDEN + * Field used for list handling. + */ sys_snode_t node; + /** @endcond */ }; /** @brief GATT authorization callback structure. */ @@ -448,13 +472,17 @@ struct bt_gatt_authorization_cb { */ #define BT_GATT_CHRC_EXT_PROP 0x80 -/** @brief Characteristic Attribute Value. */ +/** @brief Attribute Value of a Characteristic Declaration. + * + * This is the data associated with the characteristic, and can be read from or + * written to by a GATT client depending on the characteristic properties. + */ struct bt_gatt_chrc { /** Characteristic UUID. */ const struct bt_uuid *uuid; /** Characteristic Value handle. */ uint16_t value_handle; - /** Characteristic properties. */ + /** Characteristic properties, a bitmap of ``BT_GATT_CHRC_*`` macros. */ uint8_t properties; }; @@ -462,9 +490,15 @@ struct bt_gatt_chrc { #define BT_GATT_CEP_RELIABLE_WRITE 0x0001 #define BT_GATT_CEP_WRITABLE_AUX 0x0002 -/** @brief Characteristic Extended Properties Attribute Value. */ +/** @brief Characteristic Extended Properties Attribute Value. + * + * Used in the discovery of standard characteristic descriptor values. Shall + * exist if the @ref BT_GATT_CHRC_EXT_PROP bit is set in the characteristic + * properties. Can be used with the @ref BT_GATT_CEP macro to declare the CEP + * descriptor. + */ struct bt_gatt_cep { - /** Characteristic Extended properties */ + /** Characteristic Extended properties, a bitmap of ``BT_GATT_CEP_*`` macros. */ uint16_t properties; }; @@ -483,9 +517,12 @@ struct bt_gatt_cep { */ #define BT_GATT_CCC_INDICATE 0x0002 -/** Client Characteristic Configuration Attribute Value */ +/** @brief Client Characteristic Configuration Attribute Value + * + * Used in the discovery of standard characteristic descriptor values. + */ struct bt_gatt_ccc { - /** Client Characteristic Configuration flags */ + /** Client Characteristic Configuration flags, a bitmap of ``BT_GATT_CCC_*`` macros. */ uint16_t flags; }; @@ -499,25 +536,52 @@ struct bt_gatt_ccc { */ #define BT_GATT_SCC_BROADCAST 0x0001 -/** Server Characteristic Configuration Attribute Value */ +/** @brief Server Characteristic Configuration Attribute Value + * + * Used in the discovery of standard characteristic descriptor values. + */ struct bt_gatt_scc { - /** Server Characteristic Configuration flags */ + /** Server Characteristic Configuration flags, a bitmap of ``BT_GATT_SCC_*`` macros. */ uint16_t flags; }; -/** @brief GATT Characteristic Presentation Format Attribute Value. */ +/** @brief GATT Characteristic Presentation Format Attribute Value. + * + * Used in the discovery of standard characteristic descriptor values. Can be + * used with the @ref BT_GATT_CPF macro to declare the CPF descriptor. + */ struct bt_gatt_cpf { - /** Format of the value of the characteristic */ + /** @brief Format of the value of the characteristic. + * + * The format types can be found in section 2.4.1 of the Bluetooth SIG + * Assigned Numbers document. + */ uint8_t format; - /** Exponent field to determine how the value of this characteristic is - * further formatted + /** @brief Exponent field for value formatting. + * + * Only used on integer format types. + * actual value = Characteristic Value x 10^Exponent */ int8_t exponent; - /** Unit of the characteristic */ + /** @brief UUID of the unit of the characteristic. + * + * The units can be found in section 3.5 of the Bluetooth SIG Assigned + * Numbers document. + */ uint16_t unit; - /** Name space of the description */ + /** @brief Name space of the description. + * + * Used to identify the organization that is responsible for defining + * the enumerations for the description field. See section 2.4.2 of the + * Bluetooth SIG Assigned Numbers document. + */ uint8_t name_space; - /** Description of the characteristic as defined in a higher layer profile */ + /** @brief Description of the characteristic as defined in a higher layer profile. + * + * An enumerated value defined by the organization identified by the + * name_space field. See section 2.4.2.1 of the Bluetooth SIG Assigned + * Numbers document. + */ uint16_t description; }; @@ -721,8 +785,8 @@ uint16_t bt_gatt_attr_get_handle(const struct bt_gatt_attr *attr); * * @param attr A Characteristic Attribute. * - * @note The ``user_data`` of the attribute must of type @ref bt_gatt_chrc and the ``uuid`` shall be - * BT_UUID_GATT_CHRC + * @note The ``user_data`` of the attribute must be of type @ref bt_gatt_chrc and the ``uuid`` shall + * be BT_UUID_GATT_CHRC. * * @return the handle of the corresponding Characteristic Value. The value will * be zero (the invalid handle) if @p attr was not a characteristic @@ -1722,6 +1786,7 @@ struct bt_gatt_discover_params { /** Discover attribute callback */ bt_gatt_discover_func_t func; union { + /** See @ref bt_gatt_include for more on included services. */ struct { /** Include service attribute declaration handle */ uint16_t attr_handle; @@ -1841,9 +1906,9 @@ struct bt_gatt_read_params { bool variable; } multiple; struct { - /** First requested handle number. */ + /** Attribute handle to start reading from. */ uint16_t start_handle; - /** Last requested handle number. */ + /** Attribute handle to stop reading at. */ uint16_t end_handle; /** 2 or 16 octet UUID. */ const struct bt_uuid *uuid; @@ -2133,7 +2198,11 @@ struct bt_gatt_subscribe_params { /** Subscription flags */ ATOMIC_DEFINE(flags, BT_GATT_SUBSCRIBE_NUM_FLAGS); + /** @cond INTERNAL_HIDDEN + * Field used for list handling. + */ sys_snode_t node; + /** @endcond */ #if defined(CONFIG_BT_EATT) || defined(__DOXYGEN__) /** Att channel options. */ enum bt_att_chan_opt chan_opt; From 7037f5946a39d356030f467643a96860fa4f9fb4 Mon Sep 17 00:00:00 2001 From: Kyra Lengfeld Date: Mon, 3 Mar 2025 13:33:55 +0100 Subject: [PATCH 09/20] =?UTF-8?q?[nrf=20fromtree]=20Bluetooth:=20Host:=20i?= =?UTF-8?q?mprove=20more=C2=B2=20GATT=20documentation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit adds improvements for the GATT client API part. Signed-off-by: Kyra Lengfeld (cherry picked from commit b136f6da555b27a2a985aa71a8947306d3d2b645) --- include/zephyr/bluetooth/gatt.h | 94 +++++++++++++-------------------- 1 file changed, 37 insertions(+), 57 deletions(-) diff --git a/include/zephyr/bluetooth/gatt.h b/include/zephyr/bluetooth/gatt.h index 9e4ec0db993..54022b3c651 100644 --- a/include/zephyr/bluetooth/gatt.h +++ b/include/zephyr/bluetooth/gatt.h @@ -103,7 +103,7 @@ enum bt_gatt_perm { #define BT_GATT_ERR(_att_err) (-(_att_err)) /** GATT attribute write flags */ -enum { +enum bt_gatt_attr_write_flag { /** @brief Attribute prepare write flag * * If set, write callback should only check if the device is @@ -198,7 +198,7 @@ typedef ssize_t (*bt_gatt_attr_read_func_t)(struct bt_conn *conn, * @param buf Buffer with the data to write * @param len Number of bytes in the buffer * @param offset Offset to start writing from - * @param flags Flags (``BT_GATT_WRITE_FLAG_*``) + * @param flags Flags of type @ref bt_gatt_attr_write_flag * * @return Number of bytes written, or in case of an error * ``BT_GATT_ERR()`` with a specific ``BT_ATT_ERR_*`` error code. @@ -1114,7 +1114,7 @@ ssize_t bt_gatt_attr_read_ccc(struct bt_conn *conn, * @param buf Buffer to store the value read. * @param len Buffer length. * @param offset Start offset. - * @param flags Write flags. + * @param flags Write flags, see @ref bt_gatt_attr_write_flag. * * @return number of bytes written in case of success or negative values in * case of error. @@ -1123,12 +1123,11 @@ ssize_t bt_gatt_attr_read_ccc(struct bt_conn *conn, * @note Only use this with attributes which user_data is a _bt_gatt_ccc. * _bt_gatt_ccc being the internal representation of CCC value. */ - /** @endcond */ +/** @endcond */ ssize_t bt_gatt_attr_write_ccc(struct bt_conn *conn, const struct bt_gatt_attr *attr, const void *buf, uint16_t len, uint16_t offset, uint8_t flags); - /** * @brief Initialize Client Characteristic Configuration Declaration Macro. * @@ -1645,26 +1644,30 @@ uint16_t bt_gatt_get_uatt_mtu(struct bt_conn *conn); * @{ */ -/** @brief GATT Exchange MTU parameters */ +/** @brief GATT Exchange MTU parameters + * + * Used with @ref bt_gatt_exchange_mtu() to initiate an MTU exchange. The + * response is handled in the callback @p func, which is called upon + * completion from the 'config BT_RECV_CONTEXT' context. + * + * @p params must remain valid until the callback executes. + */ struct bt_gatt_exchange_params { - /** Response callback */ + /** Callback for MTU exchange response */ void (*func)(struct bt_conn *conn, uint8_t err, struct bt_gatt_exchange_params *params); }; /** @brief Exchange MTU * - * This client procedure can be used to set the MTU to the maximum possible - * size the buffers can hold. - * - * @note Shall only be used once per connection. - * - * The Response comes in callback @p params->func. The callback is run from - * the context specified by 'config BT_RECV_CONTEXT'. - * @p params must remain valid until start of callback. + * Once per connection, this client procedure can be used to set the MTU to + * the maximum possible size the buffers can hold. * - * This function will block while the ATT request queue is full, except when - * called from the BT RX thread, as this would cause a deadlock. + * As the response comes in callback @p params->func, for example + * @ref bt_gatt_get_mtu can be invoked in the mtu_exchange-callback to read + * out the new negotiated ATT connection MTU. The callback is run from the + * context specified by 'config BT_RECV_CONTEXT' and @p params must remain + * valid until start of callback. * * @param conn Connection object. * @param params Exchange MTU parameters. @@ -1674,7 +1677,7 @@ struct bt_gatt_exchange_params { * * @retval -ENOMEM ATT request queue is full and blocking would cause deadlock. * Allow a pending request to resolve before retrying, or call this function - * outside the BT RX thread to get blocking behavior. Queue size is controlled + * from a separate thread to get blocking behavior. Queue size is controlled * by @kconfig{CONFIG_BT_ATT_TX_COUNT}. * * @retval -EALREADY The MTU exchange procedure has been already performed. @@ -1733,7 +1736,7 @@ typedef uint8_t (*bt_gatt_discover_func_t)(struct bt_conn *conn, struct bt_gatt_discover_params *params); /** GATT Discover types */ -enum { +enum bt_gatt_discover_type { /** Discover Primary Services. */ BT_GATT_DISCOVER_PRIMARY, /** Discover Secondary Services. */ @@ -1834,9 +1837,6 @@ struct bt_gatt_discover_params { * the BT RX thread. @p params must remain valid until start of callback where * iter `attr` is `NULL` or callback will return `BT_GATT_ITER_STOP`. * - * This function will block while the ATT request queue is full, except when - * called from the BT RX thread, as this would cause a deadlock. - * * @param conn Connection object. * @param params Discover parameters. * @@ -1845,7 +1845,7 @@ struct bt_gatt_discover_params { * * @retval -ENOMEM ATT request queue is full and blocking would cause deadlock. * Allow a pending request to resolve before retrying, or call this function - * outside the BT RX thread to get blocking behavior. Queue size is controlled + * from a separate thread to get blocking behavior. Queue size is controlled * by @kconfig{CONFIG_BT_ATT_TX_COUNT}. */ int bt_gatt_discover(struct bt_conn *conn, @@ -1924,11 +1924,11 @@ struct bt_gatt_read_params { /** @brief Read Attribute Value by handle * - * This procedure read the attribute value and return it to the callback. + * This procedure reads the attribute value and returns it to the callback. * * When reading attributes by UUID the callback can be called multiple times - * depending on how many instances of given the UUID exists with the - * start_handle being updated for each instance. + * depending on how many instances of a given UUID exists with the start_handle + * being updated for each instance. * * To perform a GATT Long Read procedure, start with a Characteristic Value * Read (by setting @c offset @c 0 and @c handle_count @c 1) and then return @@ -1950,9 +1950,6 @@ struct bt_gatt_read_params { * the context specified by 'config BT_RECV_CONTEXT'. * @p params must remain valid until start of callback. * - * This function will block while the ATT request queue is full, except when - * called from the BT RX thread, as this would cause a deadlock. - * * @param conn Connection object. * @param params Read parameters. * @@ -1961,7 +1958,7 @@ struct bt_gatt_read_params { * * @retval -ENOMEM ATT request queue is full and blocking would cause deadlock. * Allow a pending request to resolve before retrying, or call this function - * outside the BT RX thread to get blocking behavior. Queue size is controlled + * from a separate thread to get blocking behavior. Queue size is controlled * by @kconfig{CONFIG_BT_ATT_TX_COUNT}. */ int bt_gatt_read(struct bt_conn *conn, struct bt_gatt_read_params *params); @@ -2002,11 +1999,6 @@ struct bt_gatt_write_params { * the context specified by 'config BT_RECV_CONTEXT'. * @p params must remain valid until start of callback. * - * This function will block while the ATT request queue is full, except when - * called from Bluetooth event context. When called from Bluetooth context, - * this function will instead instead return `-ENOMEM` if it would block to - * avoid a deadlock. - * * @param conn Connection object. * @param params Write parameters. * @@ -2015,8 +2007,8 @@ struct bt_gatt_write_params { * * @retval -ENOMEM ATT request queue is full and blocking would cause deadlock. * Allow a pending request to resolve before retrying, or call this function - * outside Bluetooth event context to get blocking behavior. Queue size is - * controlled by @kconfig{CONFIG_BT_ATT_TX_COUNT}. + * from a separate thread to get blocking behavior. Queue size is controlled + * by @kconfig{CONFIG_BT_ATT_TX_COUNT}. */ int bt_gatt_write(struct bt_conn *conn, struct bt_gatt_write_params *params); @@ -2032,14 +2024,11 @@ int bt_gatt_write(struct bt_conn *conn, struct bt_gatt_write_params *params); * The number of pending callbacks can be increased with the * @kconfig{CONFIG_BT_CONN_TX_MAX} option. * - * This function will block while the ATT request queue is full, except when - * called from the BT RX thread, as this would cause a deadlock. - * * @param conn Connection object. * @param handle Attribute handle. * @param data Data to be written. * @param length Data length. - * @param sign Whether to sign data + * @param sign Whether to sign data. * @param func Transmission complete callback. * @param user_data User data to be passed back to callback. * @@ -2047,7 +2036,7 @@ int bt_gatt_write(struct bt_conn *conn, struct bt_gatt_write_params *params); * * @retval -ENOMEM ATT request queue is full and blocking would cause deadlock. * Allow a pending request to resolve before retrying, or call this function - * outside the BT RX thread to get blocking behavior. Queue size is controlled + * from a separate thread to get blocking behavior. Queue size is controlled * by @kconfig{CONFIG_BT_ATT_TX_COUNT}. */ int bt_gatt_write_without_response_cb(struct bt_conn *conn, uint16_t handle, @@ -2060,20 +2049,17 @@ int bt_gatt_write_without_response_cb(struct bt_conn *conn, uint16_t handle, * This procedure write the attribute value without requiring an * acknowledgment that the write was successfully performed * - * This function will block while the ATT request queue is full, except when - * called from the BT RX thread, as this would cause a deadlock. - * * @param conn Connection object. * @param handle Attribute handle. * @param data Data to be written. * @param length Data length. - * @param sign Whether to sign data + * @param sign Whether to sign data. * * @retval 0 Successfully queued request. * * @retval -ENOMEM ATT request queue is full and blocking would cause deadlock. * Allow a pending request to resolve before retrying, or call this function - * outside the BT RX thread to get blocking behavior. Queue size is controlled + * from a separate thread to get blocking behavior. Queue size is controlled * by @kconfig{CONFIG_BT_ATT_TX_COUNT}. */ static inline int bt_gatt_write_without_response(struct bt_conn *conn, @@ -2117,7 +2103,7 @@ typedef void (*bt_gatt_subscribe_func_t)(struct bt_conn *conn, uint8_t err, struct bt_gatt_subscribe_params *params); /** Subscription flags */ -enum { +enum bt_gatt_sub_flag { /** @brief Persistence flag * * If set, indicates that the subscription is not saved @@ -2195,7 +2181,7 @@ struct bt_gatt_subscribe_params { */ bt_security_t min_security; #endif - /** Subscription flags */ + /** Subscription flags, see @ref bt_gatt_sub_flag */ ATOMIC_DEFINE(flags, BT_GATT_SUBSCRIBE_NUM_FLAGS); /** @cond INTERNAL_HIDDEN @@ -2227,9 +2213,6 @@ struct bt_gatt_subscribe_params { * valid while subscribed and cannot be reused for additional subscriptions * whilst active. * - * This function will block while the ATT request queue is full, except when - * called from the BT RX thread, as this would cause a deadlock. - * * @param conn Connection object. * @param params Subscribe parameters. * @@ -2238,7 +2221,7 @@ struct bt_gatt_subscribe_params { * * @retval -ENOMEM ATT request queue is full and blocking would cause deadlock. * Allow a pending request to resolve before retrying, or call this function - * outside the BT RX thread to get blocking behavior. Queue size is controlled + * from a separate thread to get blocking behavior. Queue size is controlled * by @kconfig{CONFIG_BT_ATT_TX_COUNT}. * * @retval -EALREADY if there already exist a subscription using the @p params. @@ -2278,9 +2261,6 @@ int bt_gatt_resubscribe(uint8_t id, const bt_addr_le_t *peer, * The Response comes in callback @p params->func. The callback is run from * the BT RX thread. * - * This function will block while the ATT request queue is full, except when - * called from the BT RX thread, as this would cause a deadlock. - * * @param conn Connection object. * @param params Subscribe parameters. The parameters shall be a @ref bt_gatt_subscribe_params from * a previous call to bt_gatt_subscribe(). @@ -2290,7 +2270,7 @@ int bt_gatt_resubscribe(uint8_t id, const bt_addr_le_t *peer, * * @retval -ENOMEM ATT request queue is full and blocking would cause deadlock. * Allow a pending request to resolve before retrying, or call this function - * outside the BT RX thread to get blocking behavior. Queue size is controlled + * from a separate thread to get blocking behavior. Queue size is controlled * by @kconfig{CONFIG_BT_ATT_TX_COUNT}. */ int bt_gatt_unsubscribe(struct bt_conn *conn, From 82843cbb0f155226ca9fb7a3e07c5e1e225cb2a1 Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Thu, 20 Feb 2025 14:43:52 +0100 Subject: [PATCH 10/20] [nrf fromtree] Bluetooth: Host: Add API for reading LE controller features The function supports reading multiple controller-based values. It is effectively a copy of struct bt_dev_le but in a more application-oriented definition. It was chosen to keep the features as an array rather than a 64-bit value, as the comparison macros work on arrays and that there already exists new bits > 64 in the core spec which is not yet supported by Zephyr. It is being smoke tested in a generic GATT client test, as the individual values may depend on several Kconfig options. Signed-off-by: Emil Gydesen (cherry picked from commit 44c5c1da3d6134ba468fa403e3ed4f8124cdb532) --- doc/releases/release-notes-4.2.rst | 6 ++ include/zephyr/bluetooth/bluetooth.h | 80 +++++++++++++++++++ include/zephyr/bluetooth/hci_types.h | 6 +- subsys/bluetooth/host/hci_core.c | 27 ++++++- subsys/bluetooth/host/hci_core.h | 6 +- .../host/gatt/general/src/gatt_client_test.c | 9 +++ 6 files changed, 129 insertions(+), 5 deletions(-) diff --git a/doc/releases/release-notes-4.2.rst b/doc/releases/release-notes-4.2.rst index 08b9bac3709..67c5919cd96 100644 --- a/doc/releases/release-notes-4.2.rst +++ b/doc/releases/release-notes-4.2.rst @@ -63,6 +63,12 @@ New APIs and options like you need to add more details, add them in the API documentation code instead. +* Bluetooth + + * Host + + * :c:func:`bt_le_get_local_features` + New Boards ********** diff --git a/include/zephyr/bluetooth/bluetooth.h b/include/zephyr/bluetooth/bluetooth.h index d724ba3b2f8..1a7888182f4 100644 --- a/include/zephyr/bluetooth/bluetooth.h +++ b/include/zephyr/bluetooth/bluetooth.h @@ -19,6 +19,7 @@ */ #include +#include #include #include @@ -48,6 +49,13 @@ extern "C" { */ #define BT_ID_DEFAULT 0 +/** + * @brief Number of octets for local supported + * + * The value of 8 correspond to page 0 in the LE Controller supported features + */ +#define BT_LE_LOCAL_SUPPORTED_FEATURES_SIZE 8 + /** Opaque type representing an advertiser. */ struct bt_le_ext_adv; @@ -517,6 +525,78 @@ size_t bt_data_get_len(const struct bt_data data[], size_t data_count); */ size_t bt_data_serialize(const struct bt_data *input, uint8_t *output); +struct bt_le_local_features { + /** + * @brief Local LE controller supported features. + * + * Refer to BT_LE_FEAT_BIT_* for values. + * Refer to the BT_FEAT_LE_* macros for value comparionson. + * See Bluetooth Core Specification, Vol 6, Part B, Section 4.6. + */ + uint8_t features[BT_LE_LOCAL_SUPPORTED_FEATURES_SIZE]; + + /** + * @brief Local LE controller supported states + * + * Refer to BT_LE_STATES_* for values. + * See Bluetooth Core Specification 6.0, Vol 4, Part E, Section 7.8.27 + */ + uint64_t states; + + /** + * @brief ACL data packet length + * + * This represents the maximum ACL HCI Data packet which can be sent from the Host to the + * Controller. + * The Host may support L2CAP and ATT MTUs larger than this value. + * See Bluetooth Core Specification, Vol 6, Part E, Section 7.8.2. + */ + uint16_t acl_mtu; + /** Total number of ACL data packets */ + uint8_t acl_pkts; + + /** + * @brief ISO data packet length + * + * This represents the maximum ISO HCI Data packet which can be sent from the Host to the + * Controller. + * ISO SDUs above this size can be fragmented assuming that the number of + * @ref bt_le_local_features.iso_pkts support the maximum size. + */ + uint16_t iso_mtu; + /** Total number of ISO data packets */ + uint8_t iso_pkts; + + /** + * @brief Maximum size of the controller resolving list. + * + * See Bluetooth Core Specification, Vol 6, Part E, Section 7.8.41. + */ + uint8_t rl_size; + + /** + * @brief Maximum advertising data length + * + * @note The maximum advertising data length also depends on advertising type. + * + * See Bluetooth Core Specification, Vol 6, Part E, Section 7.8.57. + */ + uint16_t max_adv_data_len; +}; + +/** + * @brief Get local Bluetooth LE controller features + * + * Can only be called after bt_enable() + * + * @param local_features Local features struct to be populated with information. + * + * @retval 0 Success + * @retval -EAGAIN The information is not yet available. + * @retval -EINVAL @p local_features is NULL. + */ +int bt_le_get_local_features(struct bt_le_local_features *local_features); + /** Advertising options */ enum { /** Convenience value when no options are specified. */ diff --git a/include/zephyr/bluetooth/hci_types.h b/include/zephyr/bluetooth/hci_types.h index 1a732790077..580385b4127 100644 --- a/include/zephyr/bluetooth/hci_types.h +++ b/include/zephyr/bluetooth/hci_types.h @@ -200,12 +200,14 @@ struct bt_hci_cmd_hdr { #define BT_LE_FEAT_BIT_CHANNEL_CLASSIFICATION 39 #define BT_LE_FEAT_BIT_ADV_CODING_SEL 40 #define BT_LE_FEAT_BIT_ADV_CODING_SEL_HOST 41 - +#define BT_LE_FEAT_BIT_DECISION_ADV_FILTER 42 #define BT_LE_FEAT_BIT_PAWR_ADVERTISER 43 #define BT_LE_FEAT_BIT_PAWR_SCANNER 44 - +#define BT_LE_FEAT_BIT_UNSEG_FRAMED_MODE 45 #define BT_LE_FEAT_BIT_CHANNEL_SOUNDING 46 #define BT_LE_FEAT_BIT_CHANNEL_SOUNDING_HOST 47 +#define BT_LE_FEAT_BIT_CHANNEL_SOUNDING_TONE_QUAL_IND 48 +#define BT_LE_FEAT_BIT_LL_EXTENDED_FEAT_SET 63 #define BT_LE_FEAT_TEST(feat, n) (feat[(n) >> 3] & \ BIT((n) & 7)) diff --git a/subsys/bluetooth/host/hci_core.c b/subsys/bluetooth/host/hci_core.c index 338cff5ba88..3f685ba9c78 100644 --- a/subsys/bluetooth/host/hci_core.c +++ b/subsys/bluetooth/host/hci_core.c @@ -1,12 +1,14 @@ /* hci_core.c - HCI core Bluetooth handling */ /* - * Copyright (c) 2017-2021 Nordic Semiconductor ASA + * Copyright (c) 2017-2025 Nordic Semiconductor ASA * Copyright (c) 2015-2016 Intel Corporation * * SPDX-License-Identifier: Apache-2.0 */ +#include + #include #include #include @@ -4509,6 +4511,29 @@ int bt_set_appearance(uint16_t appearance) } #endif +int bt_le_get_local_features(struct bt_le_local_features *remote_info) +{ + if (remote_info == NULL) { + return -EINVAL; + } + + if (!atomic_test_bit(bt_dev.flags, BT_DEV_READY)) { + return -EAGAIN; + } + + memcpy(remote_info->features, bt_dev.le.features, sizeof(remote_info->features)); + remote_info->states = bt_dev.le.states; + remote_info->acl_mtu = COND_CODE_1(CONFIG_BT_CONN, (bt_dev.le.acl_mtu), (0)); + remote_info->acl_pkts = COND_CODE_1(CONFIG_BT_CONN, (bt_dev.le.acl_pkts.limit), (0)); + remote_info->iso_mtu = COND_CODE_1(CONFIG_BT_ISO, (bt_dev.le.iso_mtu), (0)); + remote_info->iso_pkts = COND_CODE_1(CONFIG_BT_ISO, (bt_dev.le.iso_limit), (0)); + remote_info->rl_size = COND_CODE_1(CONFIG_BT_SMP, (bt_dev.le.rl_size), (0)); + remote_info->max_adv_data_len = + COND_CODE_1(CONFIG_BT_BROADCASTER, (bt_dev.le.max_adv_data_len), (0)); + + return 0; +} + bool bt_addr_le_is_bonded(uint8_t id, const bt_addr_le_t *addr) { if (IS_ENABLED(CONFIG_BT_SMP)) { diff --git a/subsys/bluetooth/host/hci_core.h b/subsys/bluetooth/host/hci_core.h index e501ae1d5fe..6502be80c3f 100644 --- a/subsys/bluetooth/host/hci_core.h +++ b/subsys/bluetooth/host/hci_core.h @@ -1,12 +1,14 @@ /* hci_core.h - Bluetooth HCI core access */ /* - * Copyright (c) 2021 Nordic Semiconductor ASA + * Copyright (c) 2021-2025 Nordic Semiconductor ASA * Copyright (c) 2015-2016 Intel Corporation * * SPDX-License-Identifier: Apache-2.0 */ +#include +#include #include /* LL connection parameters */ @@ -271,7 +273,7 @@ struct bt_le_per_adv_sync { struct bt_dev_le { /* LE features */ - uint8_t features[8]; + uint8_t features[BT_LE_LOCAL_SUPPORTED_FEATURES_SIZE]; /* LE states */ uint64_t states; diff --git a/tests/bsim/bluetooth/host/gatt/general/src/gatt_client_test.c b/tests/bsim/bluetooth/host/gatt/general/src/gatt_client_test.c index a754f08649f..e4b609aba42 100644 --- a/tests/bsim/bluetooth/host/gatt/general/src/gatt_client_test.c +++ b/tests/bsim/bluetooth/host/gatt/general/src/gatt_client_test.c @@ -6,6 +6,7 @@ #include +#include #include #include #include @@ -363,6 +364,7 @@ static void gatt_read(uint16_t handle, uint8_t expect_att_err) static void test_main(void) { + struct bt_le_local_features local_features; int err; bt_conn_cb_register(&conn_callbacks); @@ -372,6 +374,13 @@ static void test_main(void) TEST_FAIL("Bluetooth discover failed (err %d)", err); } + err = bt_le_get_local_features(&local_features); + TEST_ASSERT(err == 0, "Failed to get local features"); + TEST_ASSERT(local_features.acl_mtu > 0U, "Invalid ACL MTU"); + TEST_ASSERT(local_features.acl_pkts > 0U, "Invalid ACL packet count"); + TEST_ASSERT(sys_get_le64(local_features.features) > 0U, "Invalid features"); + TEST_ASSERT(local_features.states > 0U, "Invalid states"); + err = bt_le_scan_start(BT_LE_SCAN_PASSIVE, device_found); if (err != 0) { TEST_FAIL("Scanning failed to start (err %d)", err); From bfbe4b3ac18c5d42f2fec54415211e9a1640140d Mon Sep 17 00:00:00 2001 From: Axel Le Bourhis Date: Mon, 24 Feb 2025 16:26:51 +0100 Subject: [PATCH 11/20] [nrf fromtree] drivers: bluetooth: hci_nxp: fix nomem handling When allocation fails in `hci_rx_cb`, we should return immediately instead of continuing the execution of the function. Also, we need to free the allocated buffer from the heap when sending to the message queue fails to avoid memory leak. Signed-off-by: Axel Le Bourhis (cherry picked from commit 0034e12599934a2b98545d43e6f72265d175a3c2) --- drivers/bluetooth/hci/hci_nxp.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/bluetooth/hci/hci_nxp.c b/drivers/bluetooth/hci/hci_nxp.c index ad2dbfb9ec7..240924baf77 100644 --- a/drivers/bluetooth/hci/hci_nxp.c +++ b/drivers/bluetooth/hci/hci_nxp.c @@ -368,19 +368,23 @@ K_THREAD_DEFINE(nxp_hci_rx_thread, CONFIG_BT_DRV_RX_STACK_SIZE, bt_rx_thread, NU static void hci_rx_cb(uint8_t packetType, uint8_t *data, uint16_t len) { struct hci_data hci_rx_frame; + int ret; hci_rx_frame.packetType = packetType; hci_rx_frame.data = k_malloc(len); if (!hci_rx_frame.data) { LOG_ERR("Failed to allocate RX buffer"); + return; } memcpy(hci_rx_frame.data, data, len); hci_rx_frame.len = len; - if (k_msgq_put(&rx_msgq, &hci_rx_frame, K_NO_WAIT) < 0) { - LOG_ERR("Failed to push RX data to message queue"); + ret = k_msgq_put(&rx_msgq, &hci_rx_frame, K_NO_WAIT); + if (ret < 0) { + LOG_ERR("Failed to push RX data to message queue: %d", ret); + k_free(hci_rx_frame.data); } } From c7f5381b5d51309663c4fac51b838aeb41c571a6 Mon Sep 17 00:00:00 2001 From: Axel Le Bourhis Date: Fri, 21 Feb 2025 10:52:15 +0100 Subject: [PATCH 12/20] [nrf fromtree] drivers: bluetooth: hci_nxp: fix unexpected command complete event As the previous version of the MCXW71 BLE Controller wasn't sending a command complete event after setting the BD address, we used a workaround to directly send the HCI command without using zephyr's API. Now, on the latest version of MCXW72 and MCXW71, this issue is fixed, so we need to use `bt_hci_cmd_send_sync` to properly expect the command complete event. Signed-off-by: Axel Le Bourhis (cherry picked from commit e5a1c0bbe477bb52eff64f4255ff8fb79ddac0db) --- drivers/bluetooth/hci/hci_nxp.c | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/drivers/bluetooth/hci/hci_nxp.c b/drivers/bluetooth/hci/hci_nxp.c index 240924baf77..e66affeb933 100644 --- a/drivers/bluetooth/hci/hci_nxp.c +++ b/drivers/bluetooth/hci/hci_nxp.c @@ -79,7 +79,8 @@ LOG_MODULE_REGISTER(bt_driver); /* Private functions */ /* -------------------------------------------------------------------------- */ -#if defined(CONFIG_HCI_NXP_ENABLE_AUTO_SLEEP) || defined(CONFIG_HCI_NXP_SET_CAL_DATA) +#if defined(CONFIG_HCI_NXP_ENABLE_AUTO_SLEEP) || defined(CONFIG_HCI_NXP_SET_CAL_DATA) ||\ + defined(CONFIG_BT_HCI_SET_PUBLIC_ADDR) static int nxp_bt_send_vs_command(uint16_t opcode, const uint8_t *params, uint8_t params_len) { if (IS_ENABLED(CONFIG_BT_HCI_HOST)) { @@ -101,7 +102,7 @@ static int nxp_bt_send_vs_command(uint16_t opcode, const uint8_t *params, uint8_ return 0; } } -#endif /* CONFIG_HCI_NXP_ENABLE_AUTO_SLEEP || CONFIG_HCI_NXP_SET_CAL_DATA */ +#endif #if defined(CONFIG_HCI_NXP_ENABLE_AUTO_SLEEP) static int nxp_bt_enable_controller_autosleep(void) @@ -170,7 +171,10 @@ static int bt_nxp_set_mac_address(const bt_addr_t *public_addr) uint8_t addrOUI[BD_ADDR_OUI_PART_SIZE] = {BD_ADDR_OUI}; uint8_t uid[16] = {0}; uint8_t uuidLen; - uint8_t hciBuffer[12]; + uint8_t params[HCI_CMD_BT_HOST_SET_MAC_ADDR_PARAM_LENGTH] = { + BT_USER_BD, + 0x06U + }; /* If no public address is provided by the user, use a unique address made * from the device's UID (unique ID) @@ -190,18 +194,12 @@ static int bt_nxp_set_mac_address(const bt_addr_t *public_addr) bt_addr_copy((bt_addr_t *)bleDeviceAddress, public_addr); } - hciBuffer[0] = BT_HCI_H4_CMD; - memcpy((void *)&hciBuffer[1], (const void *)&opcode, 2U); - /* Set HCI parameter length */ - hciBuffer[3] = HCI_CMD_BT_HOST_SET_MAC_ADDR_PARAM_LENGTH; - /* Set command parameter ID */ - hciBuffer[4] = BT_USER_BD; - /* Set command parameter length */ - hciBuffer[5] = (uint8_t)6U; - memcpy(hciBuffer + 6U, (const void *)bleDeviceAddress, - BD_ADDR_UUID_PART_SIZE + BD_ADDR_OUI_PART_SIZE); + memcpy(¶ms[2], (const void *)bleDeviceAddress, + BD_ADDR_UUID_PART_SIZE + BD_ADDR_OUI_PART_SIZE); + /* Send the command */ - return PLATFORM_SendHciMessage(hciBuffer, 12U); + return nxp_bt_send_vs_command(opcode, params, + HCI_CMD_BT_HOST_SET_MAC_ADDR_PARAM_LENGTH); } #endif /* CONFIG_BT_HCI_SET_PUBLIC_ADDR */ From 8c875cd5798907e1ea1eb3b4d46489a99d5fc0e4 Mon Sep 17 00:00:00 2001 From: Ying Zhang Date: Fri, 28 Feb 2025 09:53:51 +0100 Subject: [PATCH 13/20] [nrf fromtree] drivers: Bluetooth: nxp: not power off BLE controller when bt disable remove the power off BLE controller function since the hci_reset cmd is enough, also for wifi-ble coex scenario, need to maintain BLE controller for some info in SMU region Signed-off-by: Ying Zhang (cherry picked from commit 6b16d103426999dbac6ce576dd6e99d876b6d520) --- drivers/bluetooth/hci/hci_nxp.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/bluetooth/hci/hci_nxp.c b/drivers/bluetooth/hci/hci_nxp.c index e66affeb933..70d640c1bd2 100644 --- a/drivers/bluetooth/hci/hci_nxp.c +++ b/drivers/bluetooth/hci/hci_nxp.c @@ -513,12 +513,6 @@ static int bt_nxp_close(const struct device *dev) if (ret) { LOG_ERR("Failed to reset BLE controller"); } - k_sleep(K_SECONDS(1)); - - ret = PLATFORM_TerminateBle(); - if (ret < 0) { - LOG_ERR("Failed to shutdown BLE controller"); - } } hci->recv = NULL; From 2b21bd4b1c2cc743f364331675ee3cd0158392da Mon Sep 17 00:00:00 2001 From: Nirav Agrawal Date: Wed, 5 Mar 2025 21:13:57 +0530 Subject: [PATCH 14/20] [nrf fromtree] bluetooth: host: perform hci-reset in bt_disable() - added HCI command to send hci-reset in bt_disable() func, and remove its call from the driver close() call. - remove rsp buf pass to 'hci_reset_complete()' func as status is already checked under 'bt_hci_cmd_send_sync()'. Signed-off-by: Nirav Agrawal (cherry picked from commit 438701fdd5133cb84b20b754334d149d805776b9) --- drivers/bluetooth/hci/hci_nxp.c | 10 ++-------- drivers/bluetooth/hci/ipc.c | 9 +-------- subsys/bluetooth/host/hci_core.c | 28 +++++++++++++++++----------- 3 files changed, 20 insertions(+), 27 deletions(-) diff --git a/drivers/bluetooth/hci/hci_nxp.c b/drivers/bluetooth/hci/hci_nxp.c index 70d640c1bd2..1b9eb60b229 100644 --- a/drivers/bluetooth/hci/hci_nxp.c +++ b/drivers/bluetooth/hci/hci_nxp.c @@ -1,5 +1,5 @@ /* - * Copyright 2023-2024 NXP + * Copyright 2023-2025 NXP * * SPDX-License-Identifier: Apache-2.0 */ @@ -507,13 +507,7 @@ static int bt_nxp_close(const struct device *dev) { struct bt_nxp_data *hci = dev->data; int ret = 0; - /* Reset the Controller */ - if (IS_ENABLED(CONFIG_BT_HCI_HOST)) { - ret = bt_hci_cmd_send_sync(BT_HCI_OP_RESET, NULL, NULL); - if (ret) { - LOG_ERR("Failed to reset BLE controller"); - } - } + hci->recv = NULL; return ret; diff --git a/drivers/bluetooth/hci/ipc.c b/drivers/bluetooth/hci/ipc.c index 1dcfdc915d9..f7091e207c3 100644 --- a/drivers/bluetooth/hci/ipc.c +++ b/drivers/bluetooth/hci/ipc.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2019 Nordic Semiconductor ASA + * Copyright 2025 NXP * * SPDX-License-Identifier: Apache-2.0 */ @@ -372,14 +373,6 @@ static int bt_ipc_close(const struct device *dev) struct ipc_data *ipc = dev->data; int err; - if (IS_ENABLED(CONFIG_BT_HCI_HOST)) { - err = bt_hci_cmd_send_sync(BT_HCI_OP_RESET, NULL, NULL); - if (err) { - LOG_ERR("Sending reset command failed with: %d", err); - return err; - } - } - err = ipc_service_deregister_endpoint(&ipc->hci_ept); if (err) { LOG_ERR("Deregistering HCI endpoint failed with: %d", err); diff --git a/subsys/bluetooth/host/hci_core.c b/subsys/bluetooth/host/hci_core.c index 3f685ba9c78..aa22f31b570 100644 --- a/subsys/bluetooth/host/hci_core.c +++ b/subsys/bluetooth/host/hci_core.c @@ -3,6 +3,7 @@ /* * Copyright (c) 2017-2025 Nordic Semiconductor ASA * Copyright (c) 2015-2016 Intel Corporation + * Copyright 2025 NXP * * SPDX-License-Identifier: Apache-2.0 */ @@ -2389,17 +2390,10 @@ static void le_ltk_request(struct net_buf *buf) } #endif /* CONFIG_BT_SMP */ -static void hci_reset_complete(struct net_buf *buf) +static void hci_reset_complete(void) { - uint8_t status = buf->data[0]; atomic_t flags; - LOG_DBG("status 0x%02x %s", status, bt_hci_err_to_str(status)); - - if (status) { - return; - } - if (IS_ENABLED(CONFIG_BT_OBSERVER)) { bt_scan_reset(); } @@ -3255,12 +3249,12 @@ static int common_init(void) if (!drv_quirk_no_reset()) { /* Send HCI_RESET */ - err = bt_hci_cmd_send_sync(BT_HCI_OP_RESET, NULL, &rsp); + err = bt_hci_cmd_send_sync(BT_HCI_OP_RESET, NULL, NULL); if (err) { return err; } - hci_reset_complete(rsp); - net_buf_unref(rsp); + + hci_reset_complete(); } /* Read Local Supported Features */ @@ -4384,6 +4378,18 @@ int bt_disable(void) disconnected_handles_reset(); #endif /* CONFIG_BT_CONN */ + /* Reset the Controller */ + if (!drv_quirk_no_reset()) { + + err = bt_hci_cmd_send_sync(BT_HCI_OP_RESET, NULL, NULL); + if (err) { + LOG_ERR("Failed to reset BLE controller"); + return err; + } + + hci_reset_complete(); + } + err = bt_hci_close(bt_dev.hci); if (err == -ENOSYS) { atomic_clear_bit(bt_dev.flags, BT_DEV_DISABLE); From bd116b6d8a48f4a0fd3ceee4a3fe6ab270d96e98 Mon Sep 17 00:00:00 2001 From: Kyra Lengfeld Date: Mon, 10 Mar 2025 15:43:11 +0100 Subject: [PATCH 15/20] [nrf fromtree] Bluetooth: Host: improve GATT documentation Clarifying `bt_gatt_attr` docs. Signed-off-by: Kyra Lengfeld (cherry picked from commit c31b96274326ab151b3cec8827ffc02f18a37b97) --- include/zephyr/bluetooth/gatt.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/include/zephyr/bluetooth/gatt.h b/include/zephyr/bluetooth/gatt.h index 54022b3c651..a2d553ad3ed 100644 --- a/include/zephyr/bluetooth/gatt.h +++ b/include/zephyr/bluetooth/gatt.h @@ -217,12 +217,6 @@ typedef ssize_t (*bt_gatt_attr_write_func_t)(struct bt_conn *conn, * While the formed GATT service is registered with the local * GATT server, pointers to this type can typically be given to * GATT server APIs, like bt_gatt_notify(). - * - * @note This type is given as an argument to the - * bt_gatt_discover() application callback, but it's not a - * proper object of this type. The field @ref perm, and methods - * read() and write() are not available, and it's unsound to - * pass the pointer to GATT server APIs. */ struct bt_gatt_attr { /** @brief Attribute Type @@ -235,7 +229,8 @@ struct bt_gatt_attr { * GATT Characteristic Presentation Format descriptor as * specified in Core Specification 3.G.3.3.3.5. * - * You can define a new Attribute Type. + * You can define a new Attirubute Type for your application specific + * use by generating a new UUID for it. */ const struct bt_uuid *uuid; @@ -1700,6 +1695,11 @@ struct bt_gatt_discover_params; * * The attribute object as well as its UUID and value objects are temporary and * must be copied to in order to cache its information. + * + * @note @ref bt_gatt_attr is given as an argument to bt_gatt_discover(), but + * it's not a proper object of this type. @ref bt_gatt_attr.perm, and methods + * bt_gatt_attr.read() and bt_gatt_attr.write() are not available, and it's + * unsound to pass the pointer to GATT server APIs. * Only the following fields of the attribute contains valid information: * - uuid UUID representing the type of attribute. * - handle Handle in the remote database. From ec0fbf0e25ffea62eeceb4977b696a6b3e9e8742 Mon Sep 17 00:00:00 2001 From: Kyra Lengfeld Date: Wed, 12 Mar 2025 12:51:57 +0100 Subject: [PATCH 16/20] [nrf fromtree] Bluetooth: Host: Improve bluetooth documentation This commit adds more detailed description to the "Bluetooth APIs" and "GAP" group within the bluetooth header. Signed-off-by: Kyra Lengfeld (cherry picked from commit 35707831fa5c920780cfe5a27b2349f50b6289d4) --- include/zephyr/bluetooth/bluetooth.h | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/include/zephyr/bluetooth/bluetooth.h b/include/zephyr/bluetooth/bluetooth.h index 1a7888182f4..d04dbfdd7c8 100644 --- a/include/zephyr/bluetooth/bluetooth.h +++ b/include/zephyr/bluetooth/bluetooth.h @@ -13,6 +13,12 @@ /** * @brief Bluetooth APIs + * @details The Bluetooth Subsystem Core APIs provide essential functionalities + * to use and manage Bluetooth based communication. These APIs include + * APIs for Bluetooth stack initialization, device discovery, + * connection management, data transmission, profiles and services. + * These APIs support both classic Bluetooth and Bluetooth Low Energy + * (LE) operations. * @defgroup bluetooth Bluetooth APIs * @ingroup connectivity * @{ @@ -35,6 +41,13 @@ extern "C" { /** * @brief Generic Access Profile (GAP) + * @details The Generic Access Profile (GAP) defines fundamental Bluetooth + * operations, including device discovery, pairing, and connection + * management. Zephyr's GAP implementation supports both classic + * Bluetooth and Bluetooth Low Energy (LE) functionalities, enabling + * roles such as Broadcaster, Observer, Peripheral, and Central. These + * roles define the device's behavior in advertising, scanning, and + * establishing connections within Bluetooth networks. * @defgroup bt_gap Generic Access Profile (GAP) * @since 1.0 * @version 1.0.0 From a8d72a193e7d7266e7d7c5886c2f3f2e50402fe2 Mon Sep 17 00:00:00 2001 From: Pavel Vasilyev Date: Tue, 4 Mar 2025 21:04:56 +0100 Subject: [PATCH 17/20] [nrf fromtree] bluetooth: host: ecc: Change log level debug This commit changes log level for already registered callback from warning to debug as this is cause unnecessary noise and doesn't indicate actual issue. Caller gets a certain error code for this case which can be handled properly. Signed-off-by: Pavel Vasilyev (cherry picked from commit 886fabaf87dd1b874c53373838765f3d30bbdaf8) --- subsys/bluetooth/host/ecc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subsys/bluetooth/host/ecc.c b/subsys/bluetooth/host/ecc.c index 6efc4f2baa9..d06af6a52e0 100644 --- a/subsys/bluetooth/host/ecc.c +++ b/subsys/bluetooth/host/ecc.c @@ -265,7 +265,7 @@ int bt_pub_key_gen(struct bt_pub_key_cb *new_cb) SYS_SLIST_FOR_EACH_CONTAINER(&pub_key_cb_slist, cb, node) { if (cb == new_cb) { - LOG_WRN("Callback already registered"); + LOG_DBG("Callback already registered"); return -EALREADY; } } From 6eca7acbcc01ed5964adf6c32d64dd38848d94c2 Mon Sep 17 00:00:00 2001 From: Herman Berget Date: Wed, 12 Mar 2025 16:26:58 +0100 Subject: [PATCH 18/20] [nrf fromtree] Bluetooth: Host: Remove experimental label from PAwR The api has not changed since its introduction some time ago, mark it as stable. Signed-off-by: Herman Berget (cherry picked from commit 8b909b4403a2bd07e81d7ae1b95eafa20a25cb50) --- subsys/bluetooth/Kconfig.adv | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/subsys/bluetooth/Kconfig.adv b/subsys/bluetooth/Kconfig.adv index 28e1dea61a2..486d7f1eded 100644 --- a/subsys/bluetooth/Kconfig.adv +++ b/subsys/bluetooth/Kconfig.adv @@ -44,8 +44,7 @@ config BT_PER_ADV to periodically get the data. config BT_PER_ADV_RSP - bool "Periodic Advertising with Responses support [EXPERIMENTAL]" - select EXPERIMENTAL + bool "Periodic Advertising with Responses support" depends on BT_PER_ADV help Select this to enable Periodic Advertising with Responses @@ -61,8 +60,7 @@ config BT_PER_ADV_SYNC manner. config BT_PER_ADV_SYNC_RSP - bool "Periodic Advertising with Responses sync support [EXPERIMENTAL]" - select EXPERIMENTAL + bool "Periodic Advertising with Responses sync support" depends on BT_OBSERVER help Select this to enable Periodic Advertising with Responses Sync From b25fe3a216eff12a38257f09c151f9ced2654683 Mon Sep 17 00:00:00 2001 From: Timothy Keys Date: Thu, 13 Mar 2025 08:29:22 +0000 Subject: [PATCH 19/20] [nrf fromtree] bluetooth: host: Remove experimental flag from LE Connection Subrating The API has not changed since it was introduced so should no longer be considered experimental. Signed-off-by: Timothy Keys (cherry picked from commit 7ef8116969a79adc4601ddc8916d00382f429142) --- doc/releases/release-notes-4.2.rst | 2 ++ subsys/bluetooth/Kconfig | 3 +-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/doc/releases/release-notes-4.2.rst b/doc/releases/release-notes-4.2.rst index 67c5919cd96..c43e03d1af7 100644 --- a/doc/releases/release-notes-4.2.rst +++ b/doc/releases/release-notes-4.2.rst @@ -69,6 +69,8 @@ New APIs and options * :c:func:`bt_le_get_local_features` + * LE Connection Subrating is no longer experimental. + New Boards ********** diff --git a/subsys/bluetooth/Kconfig b/subsys/bluetooth/Kconfig index 1665059ce33..93c867547a0 100644 --- a/subsys/bluetooth/Kconfig +++ b/subsys/bluetooth/Kconfig @@ -182,8 +182,7 @@ config BT_PATH_LOSS_MONITORING Bluetooth Core specification, Version 5.4 | Vol 6, Part B, Section 4.6.32. config BT_SUBRATING - bool "LE Connection Subrating [EXPERIMENTAL]" - select EXPERIMENTAL + bool "LE Connection Subrating" depends on !HAS_BT_CTLR || BT_CTLR_SUBRATING_SUPPORT help Enable support for LE Connection Subrating feature that is defined in the From f0f398b1e764156d4a2975cdc61ef55d518d257a Mon Sep 17 00:00:00 2001 From: Alberto Escolar Piedras Date: Mon, 17 Mar 2025 09:33:43 +0100 Subject: [PATCH 20/20] [nrf fromtree] Bluetooth: Host: ATT: Fix build warning with clang Fix the following warning att.c:734:3: warning: label followed by a declaration is a C23 extension [-Wc23-extensions] 734 | k_tid_t current_thread = k_current_get(); | ^ By wrapping that code as a compound statement Signed-off-by: Alberto Escolar Piedras (cherry picked from commit 1dab77b49f52cc956d60793d29d9d774b7e490e3) --- subsys/bluetooth/host/att.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/subsys/bluetooth/host/att.c b/subsys/bluetooth/host/att.c index 9d83ba688d9..8ba9957d3a3 100644 --- a/subsys/bluetooth/host/att.c +++ b/subsys/bluetooth/host/att.c @@ -720,7 +720,7 @@ static struct net_buf *bt_att_chan_create_pdu(struct bt_att_chan *chan, uint8_t /* Use a timeout only when responding/confirming */ timeout = BT_ATT_TIMEOUT; break; - default: + default: { k_tid_t current_thread = k_current_get(); if (current_thread == k_work_queue_thread_get(&k_sys_work_q)) { @@ -733,6 +733,7 @@ static struct net_buf *bt_att_chan_create_pdu(struct bt_att_chan *chan, uint8_t timeout = K_FOREVER; } } + } /* This will reserve headspace for lower layers */ buf = bt_l2cap_create_pdu_timeout(&att_pool, 0, timeout);