diff --git a/include/zephyr/bluetooth/bluetooth.h b/include/zephyr/bluetooth/bluetooth.h index ccd10411e22b..65d1f4a1f35a 100644 --- a/include/zephyr/bluetooth/bluetooth.h +++ b/include/zephyr/bluetooth/bluetooth.h @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -71,11 +72,16 @@ extern "C" { #define BT_ID_DEFAULT 0 /** - * @brief Number of octets for local supported + * @brief Number of octets for local supported features * - * The value of 8 correspond to page 0 in the LE Controller supported features + * The value of 8 correspond to page 0 in the LE Controller supported features. + * 24 bytes are required for all subsequent supported feature pages. */ -#define BT_LE_LOCAL_SUPPORTED_FEATURES_SIZE 8 +#define BT_LE_LOCAL_SUPPORTED_FEATURES_SIZE \ + (BT_HCI_LE_BYTES_PAGE_0_FEATURE_PAGE + \ + COND_CODE_1(CONFIG_BT_LE_MAX_LOCAL_SUPPORTED_FEATURE_PAGE, \ + CONFIG_BT_LE_MAX_LOCAL_SUPPORTED_FEATURE_PAGE * BT_HCI_LE_BYTES_PER_FEATURE_PAGE, \ + (0U))) /** Opaque type representing an advertiser. */ struct bt_le_ext_adv; diff --git a/include/zephyr/bluetooth/conn.h b/include/zephyr/bluetooth/conn.h index 8bc060bb05b5..bf8a31603b85 100644 --- a/include/zephyr/bluetooth/conn.h +++ b/include/zephyr/bluetooth/conn.h @@ -252,6 +252,27 @@ struct bt_conn_le_subrate_changed { uint16_t supervision_timeout; }; +/** Read all remote features complete callback params */ +struct bt_conn_le_read_all_remote_feat_complete { + /** @brief HCI Status from LE Read All Remote Features Complete event. + * + * The remaining parameters will be unchanged if status is not @ref BT_HCI_ERR_SUCCESS. + */ + uint8_t status; + /** Number of pages supported by remote device. */ + uint8_t max_remote_page; + /** Number of pages fetched from remote device. */ + uint8_t max_valid_page; + /** @brief Pointer to array of size 248, with feature bits of remote supported features. + * + * Page 0 being 8 bytes, with the following 10 pages of 24 bytes. + * Refer to BT_LE_FEAT_BIT_* for values. + * Refer to the BT_FEAT_LE_* macros for value comparison. + * See Bluetooth Core Specification, Vol 6, Part B, Section 4.6. + */ + const uint8_t *features; +}; + /** Connection Type */ enum __packed bt_conn_type { /** LE Connection Type */ @@ -1186,6 +1207,24 @@ int bt_conn_le_subrate_set_defaults(const struct bt_conn_le_subrate_param *param int bt_conn_le_subrate_request(struct bt_conn *conn, const struct bt_conn_le_subrate_param *params); +/** @brief Read remote feature pages. + * + * Request remote feature pages, from 0 up to pages_requested or the number + * of pages supported by the peer. There is a maximum of 10 pages. + * This function will trigger the read_all_remote_feat_complete callback + * when the procedure is completed. + * + * @kconfig_dep{CONFIG_BT_LE_EXTENDED_FEAT_SET} + * + * @param conn @ref BT_CONN_TYPE_LE connection object. + * @param pages_requested Number of feature pages to be requested from peer. + * There is a maximum of 10 pages. + * + * @return Zero on success or (negative) error code on failure. + * @return -EINVAL @p conn is not a valid @ref BT_CONN_TYPE_LE connection. + */ +int bt_conn_le_read_all_remote_features(struct bt_conn *conn, uint8_t pages_requested); + /** @brief Update the connection parameters. * * If the local device is in the peripheral role then updating the connection @@ -1877,6 +1916,25 @@ struct bt_conn_cb { const struct bt_conn_le_subrate_changed *params); #endif /* CONFIG_BT_SUBRATING */ +#if defined(CONFIG_BT_LE_EXTENDED_FEAT_SET) + /** @brief Read all remote features complete event. + * + * This callback notifies the application that a 'read all remote + * features' procedure of the connection is completed. The other params + * will not be populated if status is not @ref BT_HCI_ERR_SUCCESS. + * + * This callback can be triggered by calling @ref + * bt_conn_le_read_all_remote_features or by the procedure running + * autonomously in the controller. + * + * @param conn Connection object. + * @param params Remote features. + */ + void (*read_all_remote_feat_complete)( + struct bt_conn *conn, + const struct bt_conn_le_read_all_remote_feat_complete *params); +#endif /* CONFIG_BT_LE_EXTENDED_FEAT_SET */ + #if defined(CONFIG_BT_CHANNEL_SOUNDING) /** @brief LE CS Read Remote Supported Capabilities Complete event. * diff --git a/include/zephyr/bluetooth/hci_types.h b/include/zephyr/bluetooth/hci_types.h index 0b2c1b1a3976..a20852712394 100644 --- a/include/zephyr/bluetooth/hci_types.h +++ b/include/zephyr/bluetooth/hci_types.h @@ -207,7 +207,7 @@ struct bt_hci_cmd_hdr { #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_BIT_EXTENDED_FEAT_SET 63 #define BT_LE_FEAT_TEST(feat, n) (feat[(n) >> 3] & \ BIT((n) & 7)) @@ -284,6 +284,8 @@ struct bt_hci_cmd_hdr { BT_LE_FEAT_BIT_CHANNEL_SOUNDING) #define BT_FEAT_LE_CHANNEL_SOUNDING_HOST(feat) BT_LE_FEAT_TEST(feat, \ BT_LE_FEAT_BIT_CHANNEL_SOUNDING_HOST) +#define BT_FEAT_LE_EXTENDED_FEAT_SET(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_EXTENDED_FEAT_SET) #define BT_FEAT_LE_CIS(feat) (BT_FEAT_LE_CIS_CENTRAL(feat) | \ BT_FEAT_LE_CIS_PERIPHERAL(feat)) @@ -2438,6 +2440,22 @@ struct bt_hci_cp_le_tx_test_v4 { uint8_t ant_ids[0]; } __packed; +#define BT_HCI_OP_LE_READ_ALL_LOCAL_SUPPORTED_FEATURES BT_OP(BT_OGF_LE, 0x0087) /* 0x2087 */ +struct bt_hci_rp_le_read_all_local_supported_features { + uint8_t status; + uint8_t max_page; + uint8_t features[248]; +} __packed; + +#define BT_READ_ALL_LOCAL_FEATURES_SUPPORTED(supported_commands) \ + BT_CMD_TEST(supported_commands, 47, 2) + +#define BT_HCI_OP_LE_READ_ALL_REMOTE_FEATURES BT_OP(BT_OGF_LE, 0x0088) /* 0x2088 */ +struct bt_hci_cp_le_read_all_remote_features { + uint16_t handle; + uint8_t pages_requested; +} __packed; + #define BT_HCI_TX_TEST_POWER_MIN -0x7F #define BT_HCI_TX_TEST_POWER_MAX 0x14 @@ -3552,6 +3570,20 @@ struct bt_hci_evt_le_cis_established_v2 { uint8_t framing; } __packed; +#define BT_HCI_EVT_LE_READ_ALL_REMOTE_FEAT_COMPLETE 0x2b + +#define BT_HCI_LE_FEATURE_PAGE_MAX 10 +#define BT_HCI_LE_BYTES_PER_FEATURE_PAGE 24 +#define BT_HCI_LE_BYTES_PAGE_0_FEATURE_PAGE 8 + +struct bt_hci_evt_le_read_all_remote_feat_complete { + uint8_t status; + uint16_t handle; + uint8_t max_remote_page; + uint8_t max_valid_page; + uint8_t features[248]; +} __packed; + #define BT_HCI_LE_CS_INITIATOR_ROLE_MASK BIT(0) #define BT_HCI_LE_CS_REFLECTOR_ROLE_MASK BIT(1) @@ -4024,6 +4056,8 @@ struct bt_hci_evt_le_cs_procedure_enable_complete { #define BT_EVT_MASK_LE_ENH_CONN_COMPLETE_V2 BT_EVT_BIT(40) #define BT_EVT_MASK_LE_CIS_ESTABLISHED_V2 BT_EVT_BIT(41) +#define BT_EVT_MASK_LE_READ_ALL_REMOTE_FEAT_COMPLETE BT_EVT_BIT(42) + #define BT_EVT_MASK_LE_CS_READ_REMOTE_SUPPORTED_CAPABILITIES_COMPLETE BT_EVT_BIT(43) #define BT_EVT_MASK_LE_CS_READ_REMOTE_FAE_TABLE_COMPLETE BT_EVT_BIT(44) #define BT_EVT_MASK_LE_CS_SECURITY_ENABLE_COMPLETE BT_EVT_BIT(45) diff --git a/subsys/bluetooth/Kconfig b/subsys/bluetooth/Kconfig index 68d08819e1c3..c98c7a5ff538 100644 --- a/subsys/bluetooth/Kconfig +++ b/subsys/bluetooth/Kconfig @@ -115,6 +115,21 @@ config BT_CONN_TX help Hidden configuration that is true if ACL or broadcast ISO is enabled +config BT_LE_MAX_LOCAL_SUPPORTED_FEATURE_PAGE + int "Maximum supported feature page" + default 0 + range 0 10 + depends on BT_LE_EXTENDED_FEAT_SET + help + Maximum supported feature page that can be stored locally and fetched + from the remote connection with the LL Extended Feature Set feature. + +config BT_LE_EXTENDED_FEAT_SET + bool "LL Extended Feature Set" + depends on !HAS_BT_CTLR || BT_CTLR_EXTENDED_FEAT_SET_SUPPORT + help + Enable support for the LL Extended Feature Set feature. + if BT_CONN config BT_HCI_ACL_FLOW_CONTROL bool "Controller to Host ACL flow control support" diff --git a/subsys/bluetooth/common/Kconfig b/subsys/bluetooth/common/Kconfig index 2b7b698d8f8e..60328a1dd35a 100644 --- a/subsys/bluetooth/common/Kconfig +++ b/subsys/bluetooth/common/Kconfig @@ -119,7 +119,7 @@ config BT_BUF_ACL_RX_COUNT config BT_BUF_EVT_RX_SIZE int "Maximum supported HCI Event buffer length" - default $(UINT8_MAX) if (BT_EXT_ADV && BT_OBSERVER) || BT_PER_ADV_SYNC || BT_DF_CONNECTION_CTE_RX || BT_CLASSIC || BT_CHANNEL_SOUNDING + default $(UINT8_MAX) if (BT_EXT_ADV && BT_OBSERVER) || BT_PER_ADV_SYNC || BT_DF_CONNECTION_CTE_RX || BT_CLASSIC || BT_CHANNEL_SOUNDING || BT_LE_EXTENDED_FEAT_SET # LE Read Supported Commands command complete event. default 68 range 68 $(UINT8_MAX) diff --git a/subsys/bluetooth/controller/Kconfig b/subsys/bluetooth/controller/Kconfig index 02042b35074a..1144d742bee6 100644 --- a/subsys/bluetooth/controller/Kconfig +++ b/subsys/bluetooth/controller/Kconfig @@ -128,6 +128,9 @@ config BT_CTLR_SUBRATING_SUPPORT config BT_CTLR_CHANNEL_SOUNDING_SUPPORT bool +config BT_CTLR_EXTENDED_FEAT_SET_SUPPORT + bool + # Virtual option that all local LL implementations should select config HAS_BT_CTLR bool @@ -1174,6 +1177,14 @@ config BT_CTLR_CHANNEL_SOUNDING Enable support for Bluetooth 6.0 Channel Sounding in the Controller. +config BT_CTLR_EXTENDED_FEAT_SET + bool "LL Extended Feature Set support" + depends on BT_CTLR_EXTENDED_FEAT_SET_SUPPORT + default y if BT_LE_EXTENDED_FEAT_SET + help + Enable support for Bluetooth 6.0 LL Extended Feature Set + in the Controller. + rsource "Kconfig.df" rsource "Kconfig.ll_sw_split" rsource "Kconfig.dtm" diff --git a/subsys/bluetooth/host/conn.c b/subsys/bluetooth/host/conn.c index 9e9f18c040a0..5479721541af 100644 --- a/subsys/bluetooth/host/conn.c +++ b/subsys/bluetooth/host/conn.c @@ -3289,6 +3289,53 @@ int bt_conn_le_subrate_request(struct bt_conn *conn, } #endif /* CONFIG_BT_SUBRATING */ +#if defined(CONFIG_BT_LE_EXTENDED_FEAT_SET) +void notify_read_all_remote_feat_complete(struct bt_conn *conn, + struct bt_conn_le_read_all_remote_feat_complete *params) +{ + struct bt_conn_cb *callback; + + SYS_SLIST_FOR_EACH_CONTAINER(&conn_cbs, callback, _node) { + if (callback->read_all_remote_feat_complete != NULL) { + callback->read_all_remote_feat_complete(conn, params); + } + } + + STRUCT_SECTION_FOREACH(bt_conn_cb, cb) + { + if (cb->read_all_remote_feat_complete != NULL) { + cb->read_all_remote_feat_complete(conn, params); + } + } +} + +int bt_conn_le_read_all_remote_features(struct bt_conn *conn, uint8_t pages_requested) +{ + struct bt_hci_cp_le_read_all_remote_features *cp; + struct net_buf *buf; + + if (!bt_conn_is_type(conn, BT_CONN_TYPE_LE)) { + LOG_DBG("Invalid connection type: %u for %p", conn->type, conn); + return -EINVAL; + } + + if (pages_requested > BT_HCI_LE_FEATURE_PAGE_MAX) { + return -EINVAL; + } + + buf = bt_hci_cmd_alloc(K_FOREVER); + if (buf == NULL) { + return -ENOBUFS; + } + + cp = net_buf_add(buf, sizeof(*cp)); + cp->handle = sys_cpu_to_le16(conn->handle); + cp->pages_requested = pages_requested; + + return bt_hci_cmd_send_sync(BT_HCI_OP_LE_READ_ALL_REMOTE_FEATURES, buf, NULL); +} +#endif /* CONFIG_BT_LE_EXTENDED_FEAT_SET */ + #if defined(CONFIG_BT_CHANNEL_SOUNDING) void notify_remote_cs_capabilities(struct bt_conn *conn, uint8_t status, struct bt_conn_le_cs_capabilities *params) diff --git a/subsys/bluetooth/host/conn_internal.h b/subsys/bluetooth/host/conn_internal.h index 909c0ebd22ef..7d3cc1303942 100644 --- a/subsys/bluetooth/host/conn_internal.h +++ b/subsys/bluetooth/host/conn_internal.h @@ -512,6 +512,9 @@ void notify_path_loss_threshold_report(struct bt_conn *conn, void notify_subrate_change(struct bt_conn *conn, struct bt_conn_le_subrate_changed params); +void notify_read_all_remote_feat_complete(struct bt_conn *conn, + struct bt_conn_le_read_all_remote_feat_complete *params); + void notify_remote_cs_capabilities(struct bt_conn *conn, uint8_t status, struct bt_conn_le_cs_capabilities *params); diff --git a/subsys/bluetooth/host/hci_core.c b/subsys/bluetooth/host/hci_core.c index 11288fa9972b..e6738c8a69be 100644 --- a/subsys/bluetooth/host/hci_core.c +++ b/subsys/bluetooth/host/hci_core.c @@ -1792,13 +1792,45 @@ static void le_remote_feat_complete(struct net_buf *buf) atomic_set_bit(conn->flags, BT_CONN_LE_FEATURES_EXCHANGED); if (IS_ENABLED(CONFIG_BT_REMOTE_INFO) && - !IS_ENABLED(CONFIG_BT_REMOTE_VERSION)) { + (!IS_ENABLED(CONFIG_BT_REMOTE_VERSION) || + atomic_test_bit(conn->flags, BT_CONN_AUTO_VERSION_INFO))) { notify_remote_info(conn); } bt_conn_unref(conn); } +#if defined(CONFIG_BT_LE_EXTENDED_FEAT_SET) +static void le_read_all_remote_feat_complete(struct net_buf *buf) +{ + struct bt_hci_evt_le_read_all_remote_feat_complete *evt = (void *)buf->data; + struct bt_conn *conn; + struct bt_conn_le_read_all_remote_feat_complete params; + uint16_t handle = sys_le16_to_cpu(evt->handle); + + LOG_DBG("Read all remote feature complete: 0x%02x %s handle %u", evt->status, + bt_hci_err_to_str(evt->status), handle); + + conn = bt_conn_lookup_handle(handle, BT_CONN_TYPE_LE); + if (conn == NULL) { + LOG_ERR("Unknown conn handle 0x%04X", handle); + return; + } + + params.status = evt->status; + + if (params.status == BT_HCI_ERR_SUCCESS) { + params.max_remote_page = evt->max_remote_page; + params.max_valid_page = evt->max_valid_page; + params.features = evt->features; + } + + notify_read_all_remote_feat_complete(conn, ¶ms); + + bt_conn_unref(conn); +} +#endif /* CONFIG_BT_LE_EXTENDED_FEAT_SET */ + #if defined(CONFIG_BT_DATA_LEN_UPDATE) static void le_data_len_change(struct net_buf *buf) { @@ -2372,7 +2404,8 @@ static void bt_hci_evt_read_remote_version_complete(struct net_buf *buf) atomic_set_bit(conn->flags, BT_CONN_AUTO_VERSION_INFO); - if (IS_ENABLED(CONFIG_BT_REMOTE_INFO)) { + if (IS_ENABLED(CONFIG_BT_REMOTE_INFO) && + atomic_test_bit(conn->flags, BT_CONN_LE_FEATURES_EXCHANGED)) { /* Remote features is already present */ notify_remote_info(conn); } @@ -2920,6 +2953,11 @@ static const struct event_handler meta_events[] = { EVENT_HANDLER(BT_HCI_EVT_LE_ENH_CONN_COMPLETE_V2, le_enh_conn_complete_v2, sizeof(struct bt_hci_evt_le_enh_conn_complete_v2)), #endif /* CONFIG_BT_PER_ADV_RSP || CONFIG_BT_PER_ADV_SYNC_RSP */ +#if defined(CONFIG_BT_LE_EXTENDED_FEAT_SET) + EVENT_HANDLER(BT_HCI_EVT_LE_READ_ALL_REMOTE_FEAT_COMPLETE, + le_read_all_remote_feat_complete, + sizeof(struct bt_hci_evt_le_read_all_remote_feat_complete)), +#endif /* CONFIG_BT_LE_EXTENDED_FEAT_SET */ #endif /* CONFIG_BT_CONN */ #if defined(CONFIG_BT_CHANNEL_SOUNDING) EVENT_HANDLER(BT_HCI_EVT_LE_CS_READ_REMOTE_SUPPORTED_CAPABILITIES_COMPLETE, @@ -3156,9 +3194,47 @@ static void read_le_features_complete(struct net_buf *buf) LOG_DBG("status 0x%02x %s", rp->status, bt_hci_err_to_str(rp->status)); + memcpy(bt_dev.le.features, rp->features, sizeof(rp->features)); +} + +static void read_le_all_supported_features_complete(struct net_buf *buf) +{ + struct bt_hci_rp_le_read_all_local_supported_features *rp = (void *)buf->data; + + LOG_DBG("status 0x%02x %s", rp->status, bt_hci_err_to_str(rp->status)); + memcpy(bt_dev.le.features, rp->features, sizeof(bt_dev.le.features)); } +static int read_le_local_supported_features(void) +{ + struct net_buf *rsp; + int err; + + /* Read Low Energy Supported Features */ + if (IS_ENABLED(CONFIG_BT_LE_EXTENDED_FEAT_SET) && + BT_READ_ALL_LOCAL_FEATURES_SUPPORTED(bt_dev.supported_commands)) { + err = bt_hci_cmd_send_sync(BT_HCI_OP_LE_READ_ALL_LOCAL_SUPPORTED_FEATURES, NULL, + &rsp); + if (err != 0) { + return err; + } + + read_le_all_supported_features_complete(rsp); + } else { + err = bt_hci_cmd_send_sync(BT_HCI_OP_LE_READ_LOCAL_FEATURES, NULL, + &rsp); + if (err != 0) { + return err; + } + + read_le_features_complete(rsp); + } + + net_buf_unref(rsp); + return 0; +} + #if defined(CONFIG_BT_CONN) #if !defined(CONFIG_BT_CLASSIC) static void read_buffer_size_complete(struct net_buf *buf) @@ -3443,6 +3519,11 @@ static int le_set_event_mask(void) BT_FEAT_LE_CONN_SUBRATING(bt_dev.le.features)) { mask |= BT_EVT_MASK_LE_SUBRATE_CHANGE; } + + if (IS_ENABLED(CONFIG_BT_LE_EXTENDED_FEAT_SET) && + BT_FEAT_LE_EXTENDED_FEAT_SET(bt_dev.le.features)) { + mask |= BT_EVT_MASK_LE_READ_ALL_REMOTE_FEAT_COMPLETE; + } } if (IS_ENABLED(CONFIG_BT_SMP) && @@ -3581,16 +3662,11 @@ static int le_init(void) return -ENODEV; } - /* Read Low Energy Supported Features */ - err = bt_hci_cmd_send_sync(BT_HCI_OP_LE_READ_LOCAL_FEATURES, NULL, - &rsp); + err = read_le_local_supported_features(); if (err) { return err; } - read_le_features_complete(rsp); - net_buf_unref(rsp); - if (IS_ENABLED(CONFIG_BT_ISO) && BT_FEAT_LE_ISO(bt_dev.le.features)) { err = le_init_iso(); diff --git a/subsys/bluetooth/host/shell/bt.c b/subsys/bluetooth/host/shell/bt.c index c133608bd9d2..ab2282554dfb 100644 --- a/subsys/bluetooth/host/shell/bt.c +++ b/subsys/bluetooth/host/shell/bt.c @@ -1007,6 +1007,37 @@ void subrate_changed(struct bt_conn *conn, } #endif +#if defined(CONFIG_BT_LE_EXTENDED_FEAT_SET) +void read_all_remote_feat_complete(struct bt_conn *conn, + const struct bt_conn_le_read_all_remote_feat_complete *params) +{ + if (params->status == BT_HCI_ERR_SUCCESS) { + uint8_t number_of_bytes = BT_HCI_LE_BYTES_PAGE_0_FEATURE_PAGE; + + if (params->max_valid_page > 0) { + number_of_bytes += + (params->max_valid_page * BT_HCI_LE_BYTES_PER_FEATURE_PAGE); + } + + bt_shell_fprintf_print( + "Read all remote features complete, Max Remote Page %d, LE Features: 0x", + params->max_remote_page); + + for (int i = number_of_bytes - 1; i >= 0; i--) { + uint8_t features = params->features[i]; + char features_str[(2 * sizeof(uint8_t)) + 1]; + + bin2hex(&features, sizeof(features), features_str, sizeof(features_str)); + bt_shell_fprintf_print("%s", features_str); + } + bt_shell_fprintf_print("\n"); + } else { + bt_shell_print("Read all remote features failed (HCI status 0x%02x)", + params->status); + } +} +#endif + #if defined(CONFIG_BT_CHANNEL_SOUNDING) void print_remote_cs_capabilities(struct bt_conn *conn, uint8_t status, @@ -1186,6 +1217,9 @@ static struct bt_conn_cb conn_callbacks = { #if defined(CONFIG_BT_SUBRATING) .subrate_changed = subrate_changed, #endif +#if defined(CONFIG_BT_LE_EXTENDED_FEAT_SET) + .read_all_remote_feat_complete = read_all_remote_feat_complete, +#endif #if defined(CONFIG_BT_CHANNEL_SOUNDING) .le_cs_read_remote_capabilities_complete = print_remote_cs_capabilities, .le_cs_read_remote_fae_table_complete = print_remote_cs_fae_table, @@ -3284,6 +3318,34 @@ static int cmd_subrate_request(const struct shell *sh, size_t argc, char *argv[] } #endif +#if defined(CONFIG_BT_LE_EXTENDED_FEAT_SET) +static int cmd_read_all_remote_features(const struct shell *sh, size_t argc, char *argv[]) +{ + int err = 0; + + if (default_conn == NULL) { + shell_error(sh, "Conn handle error, at least one connection is required."); + return -ENOEXEC; + } + + uint8_t pages_requested = shell_strtoul(argv[1], 10, &err); + + if (err != 0) { + shell_help(sh); + shell_error(sh, "Could not parse input for pages_requested"); + return SHELL_CMD_HELP_PRINTED; + } + + err = bt_conn_le_read_all_remote_features(default_conn, pages_requested); + if (err != 0) { + shell_error(sh, "bt_conn_le_read_all_remote_features returned error %d", err); + return -ENOEXEC; + } + + return 0; +} +#endif + #if defined(CONFIG_BT_CONN) #if defined(CONFIG_BT_CENTRAL) static int bt_do_connect_le(int *ercd, size_t argc, char *argv[]) @@ -5035,6 +5097,10 @@ SHELL_STATIC_SUBCMD_SET_CREATE(bt_cmds, " ", cmd_subrate_request, 6, 0), #endif +#if defined(CONFIG_BT_LE_EXTENDED_FEAT_SET) + SHELL_CMD_ARG(read-all-remote-features, NULL, "", + cmd_read_all_remote_features, 2, 0), +#endif #if defined(CONFIG_BT_BROADCASTER) SHELL_CMD_ARG(advertise, NULL, " [mode: discov, non_discov] " diff --git a/tests/bluetooth/shell/testcase.yaml b/tests/bluetooth/shell/testcase.yaml index 812aee24eeb3..673f13e481ca 100644 --- a/tests/bluetooth/shell/testcase.yaml +++ b/tests/bluetooth/shell/testcase.yaml @@ -34,6 +34,12 @@ tests: - CONFIG_BT_SUBRATING=y - CONFIG_BT_LL_SW_SPLIT=n build_only: true + bluetooth.shell.extended_feature_set: + extra_configs: + - CONFIG_BT_LE_MAX_LOCAL_SUPPORTED_FEATURE_PAGE=10 + - CONFIG_BT_LE_EXTENDED_FEAT_SET=y + - CONFIG_BT_LL_SW_SPLIT=n + build_only: true bluetooth.shell.channel_sounding: extra_configs: - CONFIG_BT_CHANNEL_SOUNDING=y