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/doc/releases/release-notes-4.2.rst b/doc/releases/release-notes-4.2.rst index 08b9bac3709..c43e03d1af7 100644 --- a/doc/releases/release-notes-4.2.rst +++ b/doc/releases/release-notes-4.2.rst @@ -63,6 +63,14 @@ 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` + + * LE Connection Subrating is no longer experimental. + New Boards ********** diff --git a/drivers/bluetooth/hci/hci_nxp.c b/drivers/bluetooth/hci/hci_nxp.c index ad2dbfb9ec7..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 */ @@ -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 */ @@ -368,19 +366,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); } } @@ -505,19 +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"); - } - k_sleep(K_SECONDS(1)); - ret = PLATFORM_TerminateBle(); - if (ret < 0) { - LOG_ERR("Failed to shutdown 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/include/zephyr/bluetooth/bluetooth.h b/include/zephyr/bluetooth/bluetooth.h index d1618f98a3a..d04dbfdd7c8 100644 --- a/include/zephyr/bluetooth/bluetooth.h +++ b/include/zephyr/bluetooth/bluetooth.h @@ -13,12 +13,19 @@ /** * @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 * @{ */ #include +#include #include #include @@ -34,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 @@ -48,6 +62,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 +538,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. */ @@ -2169,8 +2262,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, diff --git a/include/zephyr/bluetooth/gatt.h b/include/zephyr/bluetooth/gatt.h index 5a20771e725..a2d553ad3ed 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 * @{ @@ -100,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 @@ -195,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. @@ -214,17 +217,11 @@ 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, 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. * @@ -232,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; @@ -275,16 +273,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 +289,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 +304,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 +317,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 +375,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 +467,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 +485,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 +512,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 +531,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; }; @@ -573,14 +632,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 +680,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 +707,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. @@ -717,7 +780,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 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 @@ -892,6 +956,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 +998,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 +1017,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 +1082,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 +1091,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,23 +1104,25 @@ 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. * @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. */ +/** @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); - /** * @brief Initialize Client Characteristic Configuration Declaration Macro. * @@ -1139,7 +1237,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 +1309,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 +1334,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 +1509,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 +1548,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 +1582,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 @@ -1524,26 +1639,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. + * Once per connection, this client procedure can be used to set the MTU to + * the maximum possible size the buffers can hold. * - * 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. - * - * 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. @@ -1553,7 +1672,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. @@ -1576,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. @@ -1612,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. */ @@ -1665,6 +1789,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; @@ -1684,7 +1809,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 */ }; @@ -1711,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. * @@ -1722,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, @@ -1783,15 +1906,16 @@ 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; } 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 */ @@ -1800,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 @@ -1826,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. * @@ -1837,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); @@ -1866,7 +1987,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 */ }; @@ -1877,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. * @@ -1890,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); @@ -1907,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. * @@ -1922,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, @@ -1935,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, @@ -1992,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 @@ -2070,11 +2181,16 @@ 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 + * Field used for list handling. + */ sys_snode_t node; -#if defined(CONFIG_BT_EATT) + /** @endcond */ +#if defined(CONFIG_BT_EATT) || defined(__DOXYGEN__) + /** Att channel options. */ enum bt_att_chan_opt chan_opt; #endif /* CONFIG_BT_EATT */ }; @@ -2097,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. * @@ -2108,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. @@ -2148,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(). @@ -2160,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, 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/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 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 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 */ 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; diff --git a/subsys/bluetooth/host/att.c b/subsys/bluetooth/host/att.c index c3fd0a8a7cf..8ba9957d3a3 100644 --- a/subsys/bluetooth/host/att.c +++ b/subsys/bluetooth/host/att.c @@ -720,13 +720,20 @@ 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: - if (k_current_get() == k_work_queue_thread_get(&k_sys_work_q)) { + default: { + 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; } } + } /* This will reserve headspace for lower layers */ buf = bt_l2cap_create_pdu_timeout(&att_pool, 0, timeout); 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; } } 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/subsys/bluetooth/host/hci_core.c b/subsys/bluetooth/host/hci_core.c index 338cff5ba88..aa22f31b570 100644 --- a/subsys/bluetooth/host/hci_core.c +++ b/subsys/bluetooth/host/hci_core.c @@ -1,12 +1,15 @@ /* 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 + * Copyright 2025 NXP * * SPDX-License-Identifier: Apache-2.0 */ +#include + #include #include #include @@ -2387,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(); } @@ -3253,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 */ @@ -4382,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); @@ -4509,6 +4517,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/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(); 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/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); 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,