From 14d8abcc3c313f3a582a108014cf51dbc5fbcc95 Mon Sep 17 00:00:00 2001 From: Adam Cavender Date: Thu, 10 Oct 2024 11:10:25 +0100 Subject: [PATCH] bluetooth: host: CS support for various HCI commands Adds HCI support for: - LE CS Security Enable - LE CS Procedure Enable - LE CS Set Procedure Parameters - LE CS Set Channel Classification - LE CS Read Local Supported Capabilities - LE CS Write Cached Remote Supported Capabilities - LE CS Write Cached Remote FAE Table Signed-off-by: Adam Cavender --- include/zephyr/bluetooth/conn.h | 101 +++++++ include/zephyr/bluetooth/cs.h | 244 +++++++++++++---- include/zephyr/bluetooth/hci_types.h | 171 ++++++++++-- subsys/bluetooth/host/conn.c | 35 +++ subsys/bluetooth/host/conn_internal.h | 5 + subsys/bluetooth/host/cs.c | 372 ++++++++++++++++++++++++++ subsys/bluetooth/host/hci_core.c | 8 + subsys/bluetooth/host/hci_core.h | 2 + subsys/bluetooth/host/shell/cs.c | 270 ++++++++++++++++++- 9 files changed, 1127 insertions(+), 81 deletions(-) diff --git a/include/zephyr/bluetooth/conn.h b/include/zephyr/bluetooth/conn.h index 8a97be8001f7e..4d2da8d7a583e 100644 --- a/include/zephyr/bluetooth/conn.h +++ b/include/zephyr/bluetooth/conn.h @@ -1518,6 +1518,86 @@ enum bt_security_err { BT_SECURITY_ERR_UNSPECIFIED, }; +enum bt_conn_le_cs_procedure_enable_state { + BT_CONN_LE_CS_PROCEDURES_DISABLED = BT_HCI_OP_LE_CS_PROCEDURES_DISABLED, + BT_CONN_LE_CS_PROCEDURES_ENABLED = BT_HCI_OP_LE_CS_PROCEDURES_ENABLED, +}; + +/** CS Test Tone Antennna Config Selection. + * + * These enum values are indices in the following table, where N_AP is the maximum + * number of antenna paths (in the range [1, 4]). + * + * +--------------+-------------+-------------------+-------------------+--------+ + * | Config Index | Total Paths | Dev A: # Antennas | Dev B: # Antennas | Config | + * +--------------+-------------+-------------------+-------------------+--------+ + * | 0 | 1 | 1 | 1 | 1:1 | + * | 1 | 2 | 2 | 1 | N_AP:1 | + * | 2 | 3 | 3 | 1 | N_AP:1 | + * | 3 | 4 | 4 | 1 | N_AP:1 | + * | 4 | 2 | 1 | 2 | 1:N_AP | + * | 5 | 3 | 1 | 3 | 1:N_AP | + * | 6 | 4 | 1 | 4 | 1:N_AP | + * | 7 | 4 | 2 | 2 | 2:2 | + * +--------------+-------------+-------------------+-------------------+--------+ + * + * There are therefore four groups of possible antenna configurations: + * + * - 1:1 configuration, where both A and B support 1 antenna each + * - 1:N_AP configuration, where A supports 1 antenna, B supports N_AP antennas, and + * N_AP is a value in the range [2, 4] + * - N_AP:1 configuration, where A supports N_AP antennas, B supports 1 antenna, and + * N_AP is a value in the range [2, 4] + * - 2:2 configuration, where both A and B support 2 antennas and N_AP = 4 + */ +enum bt_conn_le_cs_tone_antenna_config_selection { + BT_LE_CS_TONE_ANTENNA_CONFIGURATION_INDEX_ONE = BT_HCI_OP_LE_CS_ACI_0, + BT_LE_CS_TONE_ANTENNA_CONFIGURATION_INDEX_TWO = BT_HCI_OP_LE_CS_ACI_1, + BT_LE_CS_TONE_ANTENNA_CONFIGURATION_INDEX_THREE = BT_HCI_OP_LE_CS_ACI_2, + BT_LE_CS_TONE_ANTENNA_CONFIGURATION_INDEX_FOUR = BT_HCI_OP_LE_CS_ACI_3, + BT_LE_CS_TONE_ANTENNA_CONFIGURATION_INDEX_FIVE = BT_HCI_OP_LE_CS_ACI_4, + BT_LE_CS_TONE_ANTENNA_CONFIGURATION_INDEX_SIX = BT_HCI_OP_LE_CS_ACI_5, + BT_LE_CS_TONE_ANTENNA_CONFIGURATION_INDEX_SEVEN = BT_HCI_OP_LE_CS_ACI_6, + BT_LE_CS_TONE_ANTENNA_CONFIGURATION_INDEX_EIGHT = BT_HCI_OP_LE_CS_ACI_7, +}; + +struct bt_conn_le_cs_procedure_enable_complete { + /* The ID associated with the desired configuration (0 to 3) */ + uint8_t config_id; + + /* State of the CS procedure */ + enum bt_conn_le_cs_procedure_enable_state state; + + /* Antenna configuration index */ + enum bt_conn_le_cs_tone_antenna_config_selection tone_antenna_config_selection; + + /* Transmit power level used for CS procedures (-127 to 20 dB; 0x7F if unavailable) */ + int8_t selected_tx_power; + + /* Duration of each CS subevent in microseconds (1250 us to 4 s) */ + uint32_t subevent_len; + + /* Number of CS subevents anchored off the same ACL connection event (0x01 to 0x20) */ + uint8_t subevents_per_event; + + /* Time between consecutive CS subevents anchored off the same ACL connection event in + * units of 0.625 ms + */ + uint16_t subevent_interval; + + /* Number of ACL connection events between consecutive CS event anchor points */ + uint16_t event_interval; + + /* Number of ACL connection events between consecutive CS procedure anchor points */ + uint16_t procedure_interval; + + /* Number of CS procedures to be scheduled (0 if procedures to continue until disabled) */ + uint16_t procedure_count; + + /* Maximum duration for each procedure in units of 0.625 ms (0x0001 to 0xFFFF) */ + uint16_t max_procedure_len; +}; + /** @brief Connection callback structure. * * This structure is used for tracking the state of a connection. @@ -1810,6 +1890,27 @@ struct bt_conn_cb { */ void (*le_cs_subevent_data_available)(struct bt_conn *conn, struct bt_conn_le_cs_subevent_result *result); + + /** @brief LE CS Security Enabled. + * + * This callback notifies the application that a Channel Sounding + * Security Enable procedure has completed + * + * @param conn Connection object. + */ + void (*le_cs_security_enabled)(struct bt_conn *conn); + + /** @brief LE CS Procedure Enabled. + * + * This callback notifies the application that a Channel Sounding + * Procedure Enable procedure has completed + * + * @param conn Connection object. + * @param params CS Procedure Enable parameters + */ + void (*le_cs_procedure_enabled)( + struct bt_conn *conn, struct bt_conn_le_cs_procedure_enable_complete *params); + #endif /** @internal Internally used field for list handling */ diff --git a/include/zephyr/bluetooth/cs.h b/include/zephyr/bluetooth/cs.h index fa36208318000..57111a24eef4f 100644 --- a/include/zephyr/bluetooth/cs.h +++ b/include/zephyr/bluetooth/cs.h @@ -88,62 +88,24 @@ enum bt_le_cs_test_cs_sync_antenna_selection { BT_LE_CS_TEST_CS_SYNC_ANTENNA_SELECTION_FOUR = BT_HCI_OP_LE_CS_ANTENNA_SEL_FOUR, }; -/** CS Test Tone Antennna Config Selection. - * - * These enum values are indices in the following table, where N_AP is the maximum - * number of antenna paths (in the range [1, 4]). - * - * +--------------+-------------+-------------------+-------------------+--------+ - * | Config Index | Total Paths | Dev A: # Antennas | Dev B: # Antennas | Config | - * +--------------+-------------+-------------------+-------------------+--------+ - * | 0 | 1 | 1 | 1 | 1:1 | - * | 1 | 2 | 2 | 1 | N_AP:1 | - * | 2 | 3 | 3 | 1 | N_AP:1 | - * | 3 | 4 | 4 | 1 | N_AP:1 | - * | 4 | 2 | 1 | 2 | 1:N_AP | - * | 5 | 3 | 1 | 3 | 1:N_AP | - * | 6 | 4 | 1 | 4 | 1:N_AP | - * | 7 | 4 | 2 | 2 | 2:2 | - * +--------------+-------------+-------------------+-------------------+--------+ - * - * There are therefore four groups of possible antenna configurations: - * - * - 1:1 configuration, where both A and B support 1 antenna each - * - 1:N_AP configuration, where A supports 1 antenna, B supports N_AP antennas, and - * N_AP is a value in the range [2, 4] - * - N_AP:1 configuration, where A supports N_AP antennas, B supports 1 antenna, and - * N_AP is a value in the range [2, 4] - * - 2:2 configuration, where both A and B support 2 antennas and N_AP = 4 - */ -enum bt_le_cs_test_tone_antenna_config_selection { - BT_LE_CS_TEST_TONE_ANTENNA_CONFIGURATION_INDEX_ONE = BT_HCI_OP_LE_CS_TEST_ACI_0, - BT_LE_CS_TEST_TONE_ANTENNA_CONFIGURATION_INDEX_TWO = BT_HCI_OP_LE_CS_TEST_ACI_1, - BT_LE_CS_TEST_TONE_ANTENNA_CONFIGURATION_INDEX_THREE = BT_HCI_OP_LE_CS_TEST_ACI_2, - BT_LE_CS_TEST_TONE_ANTENNA_CONFIGURATION_INDEX_FOUR = BT_HCI_OP_LE_CS_TEST_ACI_3, - BT_LE_CS_TEST_TONE_ANTENNA_CONFIGURATION_INDEX_FIVE = BT_HCI_OP_LE_CS_TEST_ACI_4, - BT_LE_CS_TEST_TONE_ANTENNA_CONFIGURATION_INDEX_SIX = BT_HCI_OP_LE_CS_TEST_ACI_5, - BT_LE_CS_TEST_TONE_ANTENNA_CONFIGURATION_INDEX_SEVEN = BT_HCI_OP_LE_CS_TEST_ACI_6, - BT_LE_CS_TEST_TONE_ANTENNA_CONFIGURATION_INDEX_EIGHT = BT_HCI_OP_LE_CS_TEST_ACI_7, -}; - /** CS Test Initiator SNR control options */ -enum bt_le_cs_test_initiator_snr_control { - BT_LE_CS_TEST_INITIATOR_SNR_CONTROL_18dB = BT_HCI_OP_LE_CS_TEST_INITIATOR_SNR_18, - BT_LE_CS_TEST_INITIATOR_SNR_CONTROL_21dB = BT_HCI_OP_LE_CS_TEST_INITIATOR_SNR_21, - BT_LE_CS_TEST_INITIATOR_SNR_CONTROL_24dB = BT_HCI_OP_LE_CS_TEST_INITIATOR_SNR_24, - BT_LE_CS_TEST_INITIATOR_SNR_CONTROL_27dB = BT_HCI_OP_LE_CS_TEST_INITIATOR_SNR_27, - BT_LE_CS_TEST_INITIATOR_SNR_CONTROL_30dB = BT_HCI_OP_LE_CS_TEST_INITIATOR_SNR_30, - BT_LE_CS_TEST_INITIATOR_SNR_CONTROL_NOT_USED = BT_HCI_OP_LE_CS_TEST_INITIATOR_SNR_NOT_USED, +enum bt_le_cs_initiator_snr_control { + BT_LE_CS_INITIATOR_SNR_CONTROL_18dB = BT_HCI_OP_LE_CS_INITIATOR_SNR_18, + BT_LE_CS_INITIATOR_SNR_CONTROL_21dB = BT_HCI_OP_LE_CS_INITIATOR_SNR_21, + BT_LE_CS_INITIATOR_SNR_CONTROL_24dB = BT_HCI_OP_LE_CS_INITIATOR_SNR_24, + BT_LE_CS_INITIATOR_SNR_CONTROL_27dB = BT_HCI_OP_LE_CS_INITIATOR_SNR_27, + BT_LE_CS_INITIATOR_SNR_CONTROL_30dB = BT_HCI_OP_LE_CS_INITIATOR_SNR_30, + BT_LE_CS_INITIATOR_SNR_CONTROL_NOT_USED = BT_HCI_OP_LE_CS_INITIATOR_SNR_NOT_USED, }; /** CS Test Reflector SNR control options */ -enum bt_le_cs_test_reflector_snr_control { - BT_LE_CS_TEST_REFLECTOR_SNR_CONTROL_18dB = BT_HCI_OP_LE_CS_TEST_REFLECTOR_SNR_18, - BT_LE_CS_TEST_REFLECTOR_SNR_CONTROL_21dB = BT_HCI_OP_LE_CS_TEST_REFLECTOR_SNR_21, - BT_LE_CS_TEST_REFLECTOR_SNR_CONTROL_24dB = BT_HCI_OP_LE_CS_TEST_REFLECTOR_SNR_24, - BT_LE_CS_TEST_REFLECTOR_SNR_CONTROL_27dB = BT_HCI_OP_LE_CS_TEST_REFLECTOR_SNR_27, - BT_LE_CS_TEST_REFLECTOR_SNR_CONTROL_30dB = BT_HCI_OP_LE_CS_TEST_REFLECTOR_SNR_30, - BT_LE_CS_TEST_REFLECTOR_SNR_CONTROL_NOT_USED = BT_HCI_OP_LE_CS_TEST_REFLECTOR_SNR_NOT_USED, +enum bt_le_cs_reflector_snr_control { + BT_LE_CS_REFLECTOR_SNR_CONTROL_18dB = BT_HCI_OP_LE_CS_REFLECTOR_SNR_18, + BT_LE_CS_REFLECTOR_SNR_CONTROL_21dB = BT_HCI_OP_LE_CS_REFLECTOR_SNR_21, + BT_LE_CS_REFLECTOR_SNR_CONTROL_24dB = BT_HCI_OP_LE_CS_REFLECTOR_SNR_24, + BT_LE_CS_REFLECTOR_SNR_CONTROL_27dB = BT_HCI_OP_LE_CS_REFLECTOR_SNR_27, + BT_LE_CS_REFLECTOR_SNR_CONTROL_30dB = BT_HCI_OP_LE_CS_REFLECTOR_SNR_30, + BT_LE_CS_REFLECTOR_SNR_CONTROL_NOT_USED = BT_HCI_OP_LE_CS_REFLECTOR_SNR_NOT_USED, }; /** CS Test Override 3 T_PM Tone Extension */ @@ -351,11 +313,11 @@ struct bt_le_cs_test_param { /** Antenna Configuration Index used during antenna switching during * the tone phases of CS steps. */ - enum bt_le_cs_test_tone_antenna_config_selection tone_antenna_config_selection; + enum bt_conn_le_cs_tone_antenna_config_selection tone_antenna_config_selection; /** Initiator SNR control options */ - enum bt_le_cs_test_initiator_snr_control initiator_snr_control; + enum bt_le_cs_initiator_snr_control initiator_snr_control; /** Reflector SNR control options */ - enum bt_le_cs_test_reflector_snr_control reflector_snr_control; + enum bt_le_cs_reflector_snr_control reflector_snr_control; /** Determines octets 14 and 15 of the initial value of the DRBG nonce. */ uint16_t drbg_nonce; @@ -687,6 +649,178 @@ void bt_le_cs_step_data_parse(struct net_buf_simple *step_data_buf, bool (*func)(struct bt_le_cs_subevent_step *step, void *user_data), void *user_data); +/** @brief CS Security Enable + * + * This commmand is used to start or restart the Channel Sounding Security + * Start procedure in the local Controller for the ACL connection identified + * in the conn parameter. + * + * @note To use this API @kconfig{CONFIG_BT_CHANNEL_SOUNDING} must be set. + * + * @param conn Connection Object. + * + * @return Zero on success or (negative) error code on failure. + */ +int bt_le_cs_security_enable(struct bt_conn *conn); + +struct bt_le_cs_procedure_enable_param { + uint8_t config_id; + enum bt_conn_le_cs_procedure_enable_state enable; +}; + +/** @brief CS Procedure Enable + * + * This command is used to enable or disable the scheduling of CS procedures + * by the local Controller, with the remote device identified in the conn + * parameter. + * + * @note To use this API @kconfig{CONFIG_BT_CHANNEL_SOUNDING} must be set. + * + * @param conn Connection Object. + * @param params Parameters for the CS Procedure Enable command. + * + * @return Zero on success or (negative) error code on failure. + */ +int bt_le_cs_procedure_enable(struct bt_conn *conn, + const struct bt_le_cs_procedure_enable_param *params); + +enum bt_le_cs_procedure_phy { + BT_LE_CS_PROCEDURE_PHY_1M = BT_HCI_OP_LE_CS_PROCEDURE_PHY_1M, + BT_LE_CS_PROCEUDRE_PHY_2M = BT_HCI_OP_LE_CS_PROCEDURE_PHY_2M, + BT_LE_CS_PROCEDURE_PHY_CODED_S8 = BT_HCI_OP_LE_CS_PROCEDURE_PHY_CODED_S8, + BT_LE_CS_PROCEDURE_PHY_CODED_S2 = BT_HCI_OP_LE_CS_PROCEDURE_PHY_CODED_S2, +}; + +#define BT_LE_CS_PROCEDURE_PREFERRED_PEER_ANTENNA_1 BIT(0) +#define BT_LE_CS_PROCEDURE_PREFERRED_PEER_ANTENNA_2 BIT(1) +#define BT_LE_CS_PROCEDURE_PREFERRED_PEER_ANTENNA_3 BIT(2) +#define BT_LE_CS_PROCEDURE_PREFERRED_PEER_ANTENNA_4 BIT(3) + +struct bt_le_cs_set_procedure_parameters_param { + /* The ID associated with the desired configuration (0 to 3) */ + uint8_t config_id; + + /* Max. duration for each CS procedure, where T = N * 0.625 ms (0x0001 to 0xFFFF) */ + uint16_t max_procedure_len; + + /* Min. number of connection events between consecutive CS procedures (0x0001 to 0xFFFF) */ + uint16_t min_procedure_interval; + + /* Max. number of connection events between consecutive CS procedures (0x0001 to 0xFFFF) */ + uint16_t max_procedure_interval; + + /* Max. number of procedures to be scheduled (0x0000 for no limit; otherwise 0x0001 + * to 0xFFFF) + */ + uint16_t max_procedure_count; + + /* Min. suggested duration for each CS subevent in microseconds (1250 us to 4 s) */ + uint32_t min_subevent_len; + + /* Max. suggested duration for each CS subevent in microseconds (1250 us to 4 s) */ + uint32_t max_subevent_len; + + /* Antenna configuration index */ + enum bt_conn_le_cs_tone_antenna_config_selection tone_antenna_config_selection; + + /* Phy */ + enum bt_le_cs_procedure_phy phy; + + /* Transmit power delta, in signed dB, to indicate the recommended difference between the + * remote device's power level for the CS tones and RTT packets and the existing power + * level for the Phy indicated by the Phy parameter (0x80 for no recommendation) + */ + int8_t tx_power_delta; + + /* Preferred peer antenna (Bitmask of BT_LE_CS_PROCEDURE_PREFERRED_PEER_ANTENNA_*) */ + uint8_t preferred_peer_antenna; + + /* Initiator SNR control adjustment */ + enum bt_le_cs_initiator_snr_control snr_control_initiator; + + /* Reflector SNR control adjustment */ + enum bt_le_cs_reflector_snr_control snr_control_reflector; +}; + +/** @brief CS Set Procedure Parameters + * + * This command is used to set the parameters for the scheduling of one + * or more CS procedures by the local controller. + * + * @note To use this API @kconfig{CONFIG_BT_CHANNEL_SOUNDING} must be set. + * + * @param conn Connection Object. + * @param params Parameters for the CS Set Procedure Parameters command. + * + * @return Zero on success or (negative) error code on failure. + */ +int bt_le_cs_set_procedure_parameters(struct bt_conn *conn, + const struct bt_le_cs_set_procedure_parameters_param *params); + +/** @brief CS Set Channel Classification + * + * This command is used to update the channel classification based on + * its local information. + * + * The nth bitfield (in the range 0 to 78) contains the value for the CS + * channel index n. Channel Enabled = 1; Channel Disabled = 0. + * + * Channels n = 0, 1, 23, 24, 25, 77, and 78 shall be reserved for future + * use and shall be set to zero. At least 15 channels shall be enabled. + * + * The most significant bit (bit 79) is reserved for future use. + * + * @note To use this API, @kconfig{CONFIG_BT_CHANNEL_SOUNDING} must be set. + * + * @param channel_classification Bit fields + * + * @return Zero on success or (negative) error code on failure. + */ +int bt_le_cs_set_channel_classification(uint8_t channel_classification[10]); + +/** @brief CS Read Local Supported Capabilities + * + * This command is used to read the CS capabilities that are supported + * by the local Controller. + * + * @note To use this API @kconfig{CONFIG_BT_CHANNEL_SOUNDING} must be set. + * + * @param ret Return values for the CS Procedure Enable command. + * + * @return Zero on success or (negative) error code on failure. + */ +int bt_le_cs_read_local_supported_capabilities(struct bt_conn_le_cs_capabilities *ret); + +/** @brief CS Write Cached Remote Supported Capabilities + * + * This command is used to write the cached copy of the CS capabilities + * that are supported by the remote Controller for the connection + * identified. + * + * @note To use this API @kconfig{CONFIG_BT_CHANNEL_SOUNDING} must be set. + * + * @param conn Connection Object. + * @param params Parameters for the CS Write Cached Remote Supported Capabilities command. + * + * @return Zero on success or (negative) error code on failure. + */ +int bt_le_cs_write_cached_remote_supported_capabilities( + struct bt_conn *conn, const struct bt_conn_le_cs_capabilities *params); + +/** @brief CS Write Cached Remote FAE Table + * + * This command is used to write a cached copy of the per-channel mode-0 + * Frequency Actuation Error table of the remote device in the local Controller. + * + * @note To use this API @kconfig{CONFIG_BT_CHANNEL_SOUNDING} must be set. + * + * @param conn Connection Object. + * @param remote_fae_table Per-channel mode-0 FAE table of the local Controller + * + * @return Zero on success or (negative) error code on failure. + */ +int bt_le_cs_write_cached_remote_fae_table(struct bt_conn *conn, uint8_t remote_fae_table[72]); + #ifdef __cplusplus } #endif diff --git a/include/zephyr/bluetooth/hci_types.h b/include/zephyr/bluetooth/hci_types.h index a620097acafbe..7b9f5968f5e9c 100644 --- a/include/zephyr/bluetooth/hci_types.h +++ b/include/zephyr/bluetooth/hci_types.h @@ -2402,12 +2402,71 @@ struct bt_hci_cp_le_tx_test_v4_tx_power { int8_t tx_power; } __packed; +#define BT_HCI_OP_LE_CS_READ_LOCAL_SUPPORTED_CAPABILITIES BT_OP(BT_OGF_LE, 0x0089) /* 0x2089 */ + +struct bt_hci_rp_le_read_local_supported_capabilities { + uint8_t status; + uint8_t num_config_supported; + uint16_t max_consecutive_procedures_supported; + uint8_t num_antennas_supported; + uint8_t max_antenna_paths_supported; + uint8_t roles_supported; + uint8_t modes_supported; + uint8_t rtt_capability; + uint8_t rtt_aa_only_n; + uint8_t rtt_sounding_n; + uint8_t rtt_random_payload_n; + uint16_t nadm_sounding_capability; + uint16_t nadm_random_capability; + uint8_t cs_sync_phys_supported; + uint16_t subfeatures_supported; + uint16_t t_ip1_times_supported; + uint16_t t_ip2_times_supported; + uint16_t t_fcs_times_supported; + uint16_t t_pm_times_supported; + uint8_t t_sw_time_supported; + uint8_t tx_snr_capability; +} __packed; + #define BT_HCI_OP_LE_CS_READ_REMOTE_SUPPORTED_CAPABILITIES BT_OP(BT_OGF_LE, 0x008A) /* 0x208A */ struct bt_hci_cp_le_read_remote_supported_capabilities { uint16_t handle; } __packed; +#define BT_HCI_OP_LE_CS_WRITE_CACHED_REMOTE_SUPPORTED_CAPABILITIES \ + BT_OP(BT_OGF_LE, 0x008B) /* 0x208B */ + +struct bt_hci_cp_le_write_cached_remote_supported_capabilities { + uint16_t handle; + uint8_t num_config_supported; + uint16_t max_consecutive_procedures_supported; + uint8_t num_antennas_supported; + uint8_t max_antenna_paths_supported; + uint8_t roles_supported; + uint8_t modes_supported; + uint8_t rtt_capability; + uint8_t rtt_aa_only_n; + uint8_t rtt_sounding_n; + uint8_t rtt_random_payload_n; + uint16_t nadm_sounding_capability; + uint16_t nadm_random_capability; + uint8_t cs_sync_phys_supported; + uint16_t subfeatures_supported; + uint16_t t_ip1_times_supported; + uint16_t t_ip2_times_supported; + uint16_t t_fcs_times_supported; + uint16_t t_pm_times_supported; + uint8_t t_sw_time_supported; + uint8_t tx_snr_capability; +} __packed; + +#define BT_HCI_OP_LE_CS_SECURITY_ENABLE BT_OP(BT_OGF_LE, 0x008C) /* 0x208C */ + +struct bt_hci_cp_le_security_enable { + uint16_t handle; +} __packed; + #define BT_HCI_OP_LE_CS_SET_DEFAULT_SETTINGS BT_OP(BT_OGF_LE, 0x008D) /* 0x208D */ #define BT_HCI_OP_LE_CS_INITIATOR_ROLE_MASK BIT(0) @@ -2436,6 +2495,49 @@ struct bt_hci_cp_le_read_remote_fae_table { uint16_t handle; } __packed; +#define BT_HCI_OP_LE_CS_WRITE_CACHED_REMOTE_FAE_TABLE BT_OP(BT_OGF_LE, 0x008F) /* 0x208F */ + +struct bt_hci_cp_le_write_cached_remote_fae_table { + uint16_t handle; + uint8_t remote_fae_table[72]; +} __packed; + +#define BT_HCI_OP_LE_CS_SET_CHANNEL_CLASSIFICATION BT_OP(BT_OGF_LE, 0x0092) /* 0x2092 */ + +#define BT_HCI_OP_LE_CS_SET_PROCEDURE_PARAMETERS BT_OP(BT_OGF_LE, 0x0093) /* 0x2093 */ + +#define BT_HCI_OP_LE_CS_PROCEDURE_PHY_1M 0x01 +#define BT_HCI_OP_LE_CS_PROCEDURE_PHY_2M 0x02 +#define BT_HCI_OP_LE_CS_PROCEDURE_PHY_CODED_S8 0x03 +#define BT_HCI_OP_LE_CS_PROCEDURE_PHY_CODED_S2 0x04 + +struct bt_hci_cp_le_set_procedure_parameters { + uint16_t handle; + uint8_t config_id; + uint16_t max_procedure_len; + uint16_t min_procedure_interval; + uint16_t max_procedure_interval; + uint16_t max_procedure_count; + uint8_t min_subevent_len[3]; + uint8_t max_subevent_len[3]; + uint8_t tone_antenna_config_selection; + uint8_t phy; + uint8_t tx_power_delta; + uint8_t preferred_peer_antenna; + uint8_t snr_control_initiator; + uint8_t snr_control_reflector; +} __packed; + +#define BT_HCI_OP_LE_CS_PROCEDURE_ENABLE BT_OP(BT_OGF_LE, 0x0094) /* 0x2094 */ + +#define BT_HCI_OP_LE_CS_PROCEDURES_DISABLED 0x00 +#define BT_HCI_OP_LE_CS_PROCEDURES_ENABLED 0x01 + +struct bt_hci_cp_le_procedure_enable { + uint16_t handle; + uint8_t config_id; + uint8_t enable; +} __packed; #define BT_HCI_OP_LE_CS_TEST BT_OP(BT_OGF_LE, 0x0095) /* 0x2095 */ @@ -2466,28 +2568,28 @@ struct bt_hci_cp_le_read_remote_fae_table { #define BT_HCI_OP_LE_CS_TEST_MAXIMIZE_TX_POWER 0x7E #define BT_HCI_OP_LE_CS_TEST_MINIMIZE_TX_POWER 0x7F -#define BT_HCI_OP_LE_CS_TEST_ACI_0 0x0 -#define BT_HCI_OP_LE_CS_TEST_ACI_1 0x1 -#define BT_HCI_OP_LE_CS_TEST_ACI_2 0x2 -#define BT_HCI_OP_LE_CS_TEST_ACI_3 0x3 -#define BT_HCI_OP_LE_CS_TEST_ACI_4 0x4 -#define BT_HCI_OP_LE_CS_TEST_ACI_5 0x5 -#define BT_HCI_OP_LE_CS_TEST_ACI_6 0x6 -#define BT_HCI_OP_LE_CS_TEST_ACI_7 0x7 - -#define BT_HCI_OP_LE_CS_TEST_INITIATOR_SNR_18 0x0 -#define BT_HCI_OP_LE_CS_TEST_INITIATOR_SNR_21 0x1 -#define BT_HCI_OP_LE_CS_TEST_INITIATOR_SNR_24 0x2 -#define BT_HCI_OP_LE_CS_TEST_INITIATOR_SNR_27 0x3 -#define BT_HCI_OP_LE_CS_TEST_INITIATOR_SNR_30 0x4 -#define BT_HCI_OP_LE_CS_TEST_INITIATOR_SNR_NOT_USED 0xFF - -#define BT_HCI_OP_LE_CS_TEST_REFLECTOR_SNR_18 0x0 -#define BT_HCI_OP_LE_CS_TEST_REFLECTOR_SNR_21 0x1 -#define BT_HCI_OP_LE_CS_TEST_REFLECTOR_SNR_24 0x2 -#define BT_HCI_OP_LE_CS_TEST_REFLECTOR_SNR_27 0x3 -#define BT_HCI_OP_LE_CS_TEST_REFLECTOR_SNR_30 0x4 -#define BT_HCI_OP_LE_CS_TEST_REFLECTOR_SNR_NOT_USED 0xFF +#define BT_HCI_OP_LE_CS_ACI_0 0x0 +#define BT_HCI_OP_LE_CS_ACI_1 0x1 +#define BT_HCI_OP_LE_CS_ACI_2 0x2 +#define BT_HCI_OP_LE_CS_ACI_3 0x3 +#define BT_HCI_OP_LE_CS_ACI_4 0x4 +#define BT_HCI_OP_LE_CS_ACI_5 0x5 +#define BT_HCI_OP_LE_CS_ACI_6 0x6 +#define BT_HCI_OP_LE_CS_ACI_7 0x7 + +#define BT_HCI_OP_LE_CS_INITIATOR_SNR_18 0x0 +#define BT_HCI_OP_LE_CS_INITIATOR_SNR_21 0x1 +#define BT_HCI_OP_LE_CS_INITIATOR_SNR_24 0x2 +#define BT_HCI_OP_LE_CS_INITIATOR_SNR_27 0x3 +#define BT_HCI_OP_LE_CS_INITIATOR_SNR_30 0x4 +#define BT_HCI_OP_LE_CS_INITIATOR_SNR_NOT_USED 0xFF + +#define BT_HCI_OP_LE_CS_REFLECTOR_SNR_18 0x0 +#define BT_HCI_OP_LE_CS_REFLECTOR_SNR_21 0x1 +#define BT_HCI_OP_LE_CS_REFLECTOR_SNR_24 0x2 +#define BT_HCI_OP_LE_CS_REFLECTOR_SNR_27 0x3 +#define BT_HCI_OP_LE_CS_REFLECTOR_SNR_30 0x4 +#define BT_HCI_OP_LE_CS_REFLECTOR_SNR_NOT_USED 0xFF #define BT_HCI_OP_LE_CS_TEST_OVERRIDE_CONFIG_0_MASK BIT(0) #define BT_HCI_OP_LE_CS_TEST_OVERRIDE_CONFIG_2_MASK BIT(2) @@ -3438,6 +3540,12 @@ struct bt_hci_evt_le_cs_read_remote_fae_table_complete { #define BT_HCI_LE_CS_CONFIG_ACTION_REMOVED 0x00 #define BT_HCI_LE_CS_CONFIG_ACTION_CREATED 0x01 +#define BT_HCI_EVT_LE_CS_SECURITY_ENABLE_COMPLETE 0x2E +struct bt_hci_evt_le_cs_security_enable_complete { + uint8_t status; + uint16_t handle; +} __packed; + #define BT_HCI_EVT_LE_CS_CONFIG_COMPLETE 0x2F struct bt_hci_evt_le_cs_config_complete { uint8_t status; @@ -3700,6 +3808,23 @@ struct bt_hci_evt_le_cs_test_end_complete { uint8_t status; } __packed; +#define BT_HCI_EVT_LE_CS_PROCEDURE_ENABLE_COMPLETE 0x30 +struct bt_hci_evt_le_cs_procedure_enable_complete { + uint8_t status; + uint16_t handle; + uint8_t config_id; + uint8_t state; + uint8_t tone_antenna_config_selection; + uint8_t selected_tx_power; + uint8_t subevent_len[3]; + uint8_t subevents_per_event; + uint16_t subevent_interval; + uint16_t event_interval; + uint16_t procedure_interval; + uint16_t procedure_count; + uint16_t max_procedure_len; +} __packed; + /* Event mask bits */ #define BT_EVT_BIT(n) (1ULL << (n)) @@ -3791,7 +3916,9 @@ struct bt_hci_evt_le_cs_test_end_complete { #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) #define BT_EVT_MASK_LE_CS_CONFIG_COMPLETE BT_EVT_BIT(46) +#define BT_EVT_MASK_LE_CS_PROCEDURE_ENABLE_COMPLETE BT_EVT_BIT(47) #define BT_EVT_MASK_LE_CS_SUBEVENT_RESULT BT_EVT_BIT(48) #define BT_EVT_MASK_LE_CS_SUBEVENT_RESULT_CONTINUE BT_EVT_BIT(49) #define BT_EVT_MASK_LE_CS_TEST_END_COMPLETE BT_EVT_BIT(50) diff --git a/subsys/bluetooth/host/conn.c b/subsys/bluetooth/host/conn.c index 742801683e3d5..f4c4fa7f6fa40 100644 --- a/subsys/bluetooth/host/conn.c +++ b/subsys/bluetooth/host/conn.c @@ -3402,6 +3402,41 @@ void notify_cs_config_removed(struct bt_conn *conn, uint8_t config_id) } } +void notify_cs_security_enable_available(struct bt_conn *conn) +{ + struct bt_conn_cb *callback; + + SYS_SLIST_FOR_EACH_CONTAINER(&conn_cbs, callback, _node) { + if (callback->le_cs_security_enabled) { + callback->le_cs_security_enabled(conn); + } + } + + STRUCT_SECTION_FOREACH(bt_conn_cb, cb) { + if (cb->le_cs_security_enabled) { + cb->le_cs_security_enabled(conn); + } + } +} + +void notify_cs_procedure_enable_available(struct bt_conn *conn, + struct bt_conn_le_cs_procedure_enable_complete *params) +{ + struct bt_conn_cb *callback; + + SYS_SLIST_FOR_EACH_CONTAINER(&conn_cbs, callback, _node) { + if (callback->le_cs_procedure_enabled) { + callback->le_cs_procedure_enabled(conn, params); + } + } + + STRUCT_SECTION_FOREACH(bt_conn_cb, cb) { + if (cb->le_cs_procedure_enabled) { + cb->le_cs_procedure_enabled(conn, params); + } + } +} + void notify_cs_subevent_result(struct bt_conn *conn, struct bt_conn_le_cs_subevent_result *result) { struct bt_conn_cb *callback; diff --git a/subsys/bluetooth/host/conn_internal.h b/subsys/bluetooth/host/conn_internal.h index 4d689f0087802..5ad5aee5daa47 100644 --- a/subsys/bluetooth/host/conn_internal.h +++ b/subsys/bluetooth/host/conn_internal.h @@ -509,6 +509,11 @@ void notify_cs_config_removed(struct bt_conn *conn, uint8_t config_id); void notify_cs_subevent_result(struct bt_conn *conn, struct bt_conn_le_cs_subevent_result *result); +void notify_cs_security_enable_available(struct bt_conn *conn); + +void notify_cs_procedure_enable_available(struct bt_conn *conn, + struct bt_conn_le_cs_procedure_enable_complete *params); + #if defined(CONFIG_BT_SMP) /* If role specific LTK is present */ bool bt_conn_ltk_present(const struct bt_conn *conn); diff --git a/subsys/bluetooth/host/cs.c b/subsys/bluetooth/host/cs.c index 5a09c01726188..b22877d31b8ac 100644 --- a/subsys/bluetooth/host/cs.c +++ b/subsys/bluetooth/host/cs.c @@ -877,6 +877,378 @@ int bt_le_cs_remove_config(struct bt_conn *conn, uint8_t config_id) return bt_hci_cmd_send_sync(BT_HCI_OP_LE_CS_REMOVE_CONFIG, buf, NULL); } +int bt_le_cs_security_enable(struct bt_conn *conn) +{ + struct bt_hci_cp_le_security_enable *cp; + struct net_buf *buf; + + buf = bt_hci_cmd_create(BT_HCI_OP_LE_CS_SECURITY_ENABLE, sizeof(*cp)); + if (!buf) { + return -ENOBUFS; + } + + cp = net_buf_add(buf, sizeof(*cp)); + cp->handle = sys_cpu_to_le16(conn->handle); + + return bt_hci_cmd_send_sync(BT_HCI_OP_LE_CS_SECURITY_ENABLE, buf, NULL); +} + +int bt_le_cs_procedure_enable(struct bt_conn *conn, + const struct bt_le_cs_procedure_enable_param *params) +{ + struct bt_hci_cp_le_procedure_enable *cp; + struct net_buf *buf; + + buf = bt_hci_cmd_create(BT_HCI_OP_LE_CS_PROCEDURE_ENABLE, sizeof(*cp)); + if (!buf) { + return -ENOBUFS; + } + + cp = net_buf_add(buf, sizeof(*cp)); + cp->handle = sys_cpu_to_le16(conn->handle); + cp->config_id = params->config_id; + cp->enable = params->enable; + + return bt_hci_cmd_send_sync(BT_HCI_OP_LE_CS_PROCEDURE_ENABLE, buf, NULL); +} + +int bt_le_cs_set_procedure_parameters(struct bt_conn *conn, + const struct bt_le_cs_set_procedure_parameters_param *params) +{ + struct bt_hci_cp_le_set_procedure_parameters *cp; + struct net_buf *buf; + + buf = bt_hci_cmd_create(BT_HCI_OP_LE_CS_SET_PROCEDURE_PARAMETERS, sizeof(*cp)); + if (!buf) { + return -ENOBUFS; + } + + cp = net_buf_add(buf, sizeof(*cp)); + cp->handle = sys_cpu_to_le16(conn->handle); + cp->config_id = params->config_id; + cp->max_procedure_len = sys_cpu_to_le16(params->max_procedure_len); + cp->min_procedure_interval = sys_cpu_to_le16(params->min_procedure_interval); + cp->max_procedure_interval = sys_cpu_to_le16(params->max_procedure_interval); + cp->max_procedure_count = sys_cpu_to_le16(params->max_procedure_count); + sys_put_le24(params->min_subevent_len, cp->min_subevent_len); + sys_put_le24(params->max_subevent_len, cp->max_subevent_len); + cp->tone_antenna_config_selection = params->tone_antenna_config_selection; + cp->phy = params->phy; + cp->tx_power_delta = params->tx_power_delta; + cp->preferred_peer_antenna = params->preferred_peer_antenna; + cp->snr_control_initiator = params->snr_control_initiator; + cp->snr_control_reflector = params->snr_control_reflector; + + return bt_hci_cmd_send_sync(BT_HCI_OP_LE_CS_SET_PROCEDURE_PARAMETERS, buf, NULL); +} + +int bt_le_cs_set_channel_classification(uint8_t channel_classification[10]) +{ + uint8_t *cp; + struct net_buf *buf; + + buf = bt_hci_cmd_create(BT_HCI_OP_LE_CS_SET_CHANNEL_CLASSIFICATION, 10); + if (!buf) { + return -ENOBUFS; + } + + cp = net_buf_add(buf, 10); + memcpy(cp, channel_classification, 10); + + return bt_hci_cmd_send_sync(BT_HCI_OP_LE_CS_SET_CHANNEL_CLASSIFICATION, buf, NULL); +} + +int bt_le_cs_read_local_supported_capabilities(struct bt_conn_le_cs_capabilities *ret) +{ + struct bt_hci_rp_le_read_local_supported_capabilities *rp; + struct net_buf *rsp; + + int err = + bt_hci_cmd_send_sync(BT_HCI_OP_LE_CS_READ_LOCAL_SUPPORTED_CAPABILITIES, NULL, &rsp); + + if (err) { + return err; + } + + rp = (void *)rsp->data; + + uint8_t status = rp->status; + + ret->num_config_supported = rp->num_config_supported; + ret->max_consecutive_procedures_supported = + sys_le16_to_cpu(rp->max_consecutive_procedures_supported); + ret->num_antennas_supported = rp->num_antennas_supported; + ret->max_antenna_paths_supported = rp->max_antenna_paths_supported; + + ret->initiator_supported = rp->roles_supported & BT_HCI_LE_CS_INITIATOR_ROLE_MASK; + ret->reflector_supported = rp->roles_supported & BT_HCI_LE_CS_REFLECTOR_ROLE_MASK; + ret->mode_3_supported = rp->modes_supported & BT_HCI_LE_CS_MODES_SUPPORTED_MODE_3_MASK; + + ret->rtt_aa_only_n = rp->rtt_aa_only_n; + ret->rtt_sounding_n = rp->rtt_sounding_n; + ret->rtt_random_payload_n = rp->rtt_random_payload_n; + + if (rp->rtt_aa_only_n) { + if (rp->rtt_capability & BT_HCI_LE_CS_RTT_AA_ONLY_N_10NS_MASK) { + ret->rtt_aa_only_precision = BT_CONN_LE_CS_RTT_AA_ONLY_10NS; + } else { + ret->rtt_aa_only_precision = BT_CONN_LE_CS_RTT_AA_ONLY_150NS; + } + } else { + ret->rtt_aa_only_precision = BT_CONN_LE_CS_RTT_AA_ONLY_NOT_SUPP; + } + + if (rp->rtt_sounding_n) { + if (rp->rtt_capability & BT_HCI_LE_CS_RTT_SOUNDING_N_10NS_MASK) { + ret->rtt_sounding_precision = BT_CONN_LE_CS_RTT_SOUNDING_10NS; + } else { + ret->rtt_sounding_precision = BT_CONN_LE_CS_RTT_SOUNDING_150NS; + } + } else { + ret->rtt_sounding_precision = BT_CONN_LE_CS_RTT_SOUNDING_NOT_SUPP; + } + + if (rp->rtt_random_payload_n) { + if (rp->rtt_capability & BT_HCI_LE_CS_RTT_RANDOM_PAYLOAD_N_10NS_MASK) { + ret->rtt_random_payload_precision = BT_CONN_LE_CS_RTT_RANDOM_PAYLOAD_10NS; + } else { + ret->rtt_random_payload_precision = BT_CONN_LE_CS_RTT_RANDOM_PAYLOAD_150NS; + } + } else { + ret->rtt_random_payload_precision = BT_CONN_LE_CS_RTT_RANDOM_PAYLOAD_NOT_SUPP; + } + + ret->phase_based_nadm_sounding_supported = + sys_le16_to_cpu(rp->nadm_sounding_capability) & + BT_HCI_LE_CS_NADM_SOUNDING_CAPABILITY_PHASE_BASED_MASK; + + ret->phase_based_nadm_random_supported = + sys_le16_to_cpu(rp->nadm_random_capability) & + BT_HCI_LE_CS_NADM_RANDOM_CAPABILITY_PHASE_BASED_MASK; + + ret->cs_sync_2m_phy_supported = rp->cs_sync_phys_supported & BT_HCI_LE_CS_SYNC_PHYS_2M_MASK; + + ret->cs_sync_2m_2bt_phy_supported = + rp->cs_sync_phys_supported & BT_HCI_LE_CS_SYNC_PHYS_2M_2BT_MASK; + + ret->cs_without_fae_supported = + sys_le16_to_cpu(rp->subfeatures_supported) & BT_HCI_LE_CS_SUBFEATURE_NO_TX_FAE_MASK; + + ret->chsel_alg_3c_supported = sys_le16_to_cpu(rp->subfeatures_supported) & + BT_HCI_LE_CS_SUBFEATURE_CHSEL_ALG_3C_MASK; + + ret->pbr_from_rtt_sounding_seq_supported = + sys_le16_to_cpu(rp->subfeatures_supported) & + BT_HCI_LE_CS_SUBFEATURE_PBR_FROM_RTT_SOUNDING_SEQ_MASK; + + ret->t_ip1_times_supported = sys_le16_to_cpu(rp->t_ip1_times_supported); + ret->t_ip2_times_supported = sys_le16_to_cpu(rp->t_ip2_times_supported); + ret->t_fcs_times_supported = sys_le16_to_cpu(rp->t_fcs_times_supported); + ret->t_pm_times_supported = sys_le16_to_cpu(rp->t_pm_times_supported); + + ret->t_sw_time = rp->t_sw_time_supported; + ret->tx_snr_capability = rp->tx_snr_capability; + + net_buf_unref(rsp); + return status; +} + +int bt_le_cs_write_cached_remote_supported_capabilities( + struct bt_conn *conn, const struct bt_conn_le_cs_capabilities *params) +{ + struct bt_hci_cp_le_write_cached_remote_supported_capabilities *cp; + struct net_buf *buf; + + buf = bt_hci_cmd_create(BT_HCI_OP_LE_CS_WRITE_CACHED_REMOTE_SUPPORTED_CAPABILITIES, + sizeof(*cp)); + + if (!buf) { + return -ENOBUFS; + } + + cp = net_buf_add(buf, sizeof(*cp)); + + cp->handle = sys_cpu_to_le16(conn->handle); + + cp->num_config_supported = params->num_config_supported; + + cp->max_consecutive_procedures_supported = + sys_cpu_to_le16(params->max_consecutive_procedures_supported); + + cp->num_antennas_supported = params->num_antennas_supported; + cp->max_antenna_paths_supported = params->max_antenna_paths_supported; + + cp->roles_supported = 0; + if (params->initiator_supported) { + cp->roles_supported |= BT_HCI_LE_CS_INITIATOR_ROLE_MASK; + } + if (params->reflector_supported) { + cp->roles_supported |= BT_HCI_LE_CS_REFLECTOR_ROLE_MASK; + } + + cp->modes_supported = 0; + if (params->mode_3_supported) { + cp->modes_supported |= BT_HCI_LE_CS_MODES_SUPPORTED_MODE_3_MASK; + } + + cp->rtt_aa_only_n = params->rtt_aa_only_n; + cp->rtt_sounding_n = params->rtt_sounding_n; + cp->rtt_random_payload_n = params->rtt_random_payload_n; + + cp->rtt_capability = 0; + if (params->rtt_aa_only_precision == BT_CONN_LE_CS_RTT_AA_ONLY_10NS) { + cp->rtt_capability |= BT_HCI_LE_CS_RTT_AA_ONLY_N_10NS_MASK; + } + + if (params->rtt_sounding_precision == BT_CONN_LE_CS_RTT_SOUNDING_10NS) { + cp->rtt_capability |= BT_HCI_LE_CS_RTT_SOUNDING_N_10NS_MASK; + } + + if (params->rtt_random_payload_precision == BT_CONN_LE_CS_RTT_RANDOM_PAYLOAD_10NS) { + cp->rtt_capability |= BT_HCI_LE_CS_RTT_RANDOM_PAYLOAD_N_10NS_MASK; + } + + cp->nadm_sounding_capability = 0; + if (params->phase_based_nadm_sounding_supported) { + cp->nadm_sounding_capability |= + sys_cpu_to_le16(BT_HCI_LE_CS_NADM_SOUNDING_CAPABILITY_PHASE_BASED_MASK); + } + + cp->nadm_random_capability = 0; + if (params->phase_based_nadm_random_supported) { + cp->nadm_random_capability |= + sys_cpu_to_le16(BT_HCI_LE_CS_NADM_RANDOM_CAPABILITY_PHASE_BASED_MASK); + } + + cp->cs_sync_phys_supported = 0; + if (params->cs_sync_2m_phy_supported) { + cp->cs_sync_phys_supported |= BT_HCI_LE_CS_SYNC_PHYS_2M_MASK; + } + if (params->cs_sync_2m_2bt_phy_supported) { + cp->cs_sync_phys_supported |= BT_HCI_LE_CS_SYNC_PHYS_2M_2BT_MASK; + } + + cp->subfeatures_supported = 0; + if (params->cs_without_fae_supported) { + cp->subfeatures_supported |= + sys_cpu_to_le16(BT_HCI_LE_CS_SUBFEATURE_NO_TX_FAE_MASK); + } + if (params->chsel_alg_3c_supported) { + cp->subfeatures_supported |= + sys_cpu_to_le16(BT_HCI_LE_CS_SUBFEATURE_CHSEL_ALG_3C_MASK); + } + if (params->pbr_from_rtt_sounding_seq_supported) { + cp->subfeatures_supported |= + sys_cpu_to_le16(BT_HCI_LE_CS_SUBFEATURE_PBR_FROM_RTT_SOUNDING_SEQ_MASK); + } + + cp->t_ip1_times_supported = sys_cpu_to_le16(params->t_ip1_times_supported); + cp->t_ip2_times_supported = sys_cpu_to_le16(params->t_ip2_times_supported); + cp->t_fcs_times_supported = sys_cpu_to_le16(params->t_fcs_times_supported); + cp->t_pm_times_supported = sys_cpu_to_le16(params->t_pm_times_supported); + cp->t_sw_time_supported = params->t_sw_time; + cp->tx_snr_capability = params->tx_snr_capability; + + return bt_hci_cmd_send_sync(BT_HCI_OP_LE_CS_WRITE_CACHED_REMOTE_SUPPORTED_CAPABILITIES, buf, + NULL); +} + +int bt_le_cs_write_cached_remote_fae_table(struct bt_conn *conn, uint8_t remote_fae_table[72]) +{ + struct bt_hci_cp_le_write_cached_remote_fae_table *cp; + struct net_buf *buf; + + buf = bt_hci_cmd_create(BT_HCI_OP_LE_CS_WRITE_CACHED_REMOTE_FAE_TABLE, sizeof(*cp)); + if (!buf) { + return -ENOBUFS; + } + + cp = net_buf_add(buf, sizeof(*cp)); + + cp->handle = sys_cpu_to_le16(conn->handle); + memcpy(cp->remote_fae_table, remote_fae_table, sizeof(cp->remote_fae_table)); + + return bt_hci_cmd_send_sync(BT_HCI_OP_LE_CS_WRITE_CACHED_REMOTE_FAE_TABLE, buf, NULL); +} + +void bt_hci_le_cs_security_enable_complete(struct net_buf *buf) +{ + struct bt_conn *conn; + + struct bt_hci_evt_le_cs_security_enable_complete *evt; + + if (buf->len < sizeof(*evt)) { + LOG_ERR("Unexpected end of buffer"); + return; + } + + evt = net_buf_pull_mem(buf, sizeof(*evt)); + if (evt->status) { + LOG_INF("Security Enable failed with status 0x%02X", evt->status); + return; + } + + conn = bt_conn_lookup_handle(sys_le16_to_cpu(evt->handle), BT_CONN_TYPE_LE); + if (!conn) { + LOG_ERR("Can't lookup conn handle when reading Security Enable Complete event"); + return; + } + + notify_cs_security_enable_available(conn); + + bt_conn_unref(conn); +} + +void bt_hci_le_cs_procedure_enable_complete(struct net_buf *buf) +{ + struct bt_conn *conn; + + struct bt_hci_evt_le_cs_procedure_enable_complete *evt; + struct bt_conn_le_cs_procedure_enable_complete params; + + if (buf->len < sizeof(*evt)) { + LOG_ERR("Unexpected end of buffer"); + return; + } + + evt = net_buf_pull_mem(buf, sizeof(*evt)); + if (evt->status) { + LOG_INF("Procedure Enable failed with status 0x%02X", evt->status); + return; + } + + conn = bt_conn_lookup_handle(sys_le16_to_cpu(evt->handle), BT_CONN_TYPE_LE); + if (!conn) { + LOG_ERR("Can't lookup conn handle when reading Procedure Enable Complete event"); + return; + } + + if (evt->state == BT_HCI_OP_LE_CS_PROCEDURES_DISABLED) { + struct net_buf *reassembly_buf = get_reassembly_buf(conn->handle, false); + + if (reassembly_buf) { + LOG_WRN("De-allocating a dangling reassembly buffer"); + free_reassembly_buf(&reassembly_buf); + } + } + + params.config_id = evt->config_id; + params.state = evt->state; + params.tone_antenna_config_selection = evt->tone_antenna_config_selection; + params.selected_tx_power = evt->selected_tx_power; + params.subevent_len = sys_get_le24(evt->subevent_len); + params.subevents_per_event = evt->subevents_per_event; + params.subevent_interval = sys_le16_to_cpu(evt->subevent_interval); + params.event_interval = sys_le16_to_cpu(evt->event_interval); + params.procedure_interval = sys_le16_to_cpu(evt->procedure_interval); + params.procedure_count = sys_le16_to_cpu(evt->procedure_count); + params.max_procedure_len = sys_le16_to_cpu(evt->max_procedure_len); + + notify_cs_procedure_enable_available(conn, ¶ms); + + bt_conn_unref(conn); +} + #if defined(CONFIG_BT_CHANNEL_SOUNDING_TEST) int bt_le_cs_stop_test(void) { diff --git a/subsys/bluetooth/host/hci_core.c b/subsys/bluetooth/host/hci_core.c index bb476dd328dd2..57f544dd11e93 100644 --- a/subsys/bluetooth/host/hci_core.c +++ b/subsys/bluetooth/host/hci_core.c @@ -2830,6 +2830,12 @@ static const struct event_handler meta_events[] = { sizeof(struct bt_hci_evt_le_cs_read_remote_fae_table_complete)), EVENT_HANDLER(BT_HCI_EVT_LE_CS_CONFIG_COMPLETE, bt_hci_le_cs_config_complete_event, sizeof(struct bt_hci_evt_le_cs_config_complete)), + EVENT_HANDLER(BT_HCI_EVT_LE_CS_SECURITY_ENABLE_COMPLETE, + bt_hci_le_cs_security_enable_complete, + sizeof(struct bt_hci_evt_le_cs_security_enable_complete)), + EVENT_HANDLER(BT_HCI_EVT_LE_CS_PROCEDURE_ENABLE_COMPLETE, + bt_hci_le_cs_procedure_enable_complete, + sizeof(struct bt_hci_evt_le_cs_procedure_enable_complete)), EVENT_HANDLER(BT_HCI_EVT_LE_CS_SUBEVENT_RESULT, bt_hci_le_cs_subevent_result, sizeof(struct bt_hci_evt_le_cs_subevent_result)), @@ -3418,6 +3424,8 @@ static int le_set_event_mask(void) mask |= BT_EVT_MASK_LE_CS_READ_REMOTE_SUPPORTED_CAPABILITIES_COMPLETE; mask |= BT_EVT_MASK_LE_CS_READ_REMOTE_FAE_TABLE_COMPLETE; mask |= BT_EVT_MASK_LE_CS_CONFIG_COMPLETE; + mask |= BT_EVT_MASK_LE_CS_SECURITY_ENABLE_COMPLETE; + mask |= BT_EVT_MASK_LE_CS_PROCEDURE_ENABLE_COMPLETE; mask |= BT_EVT_MASK_LE_CS_SUBEVENT_RESULT; mask |= BT_EVT_MASK_LE_CS_SUBEVENT_RESULT_CONTINUE; mask |= BT_EVT_MASK_LE_CS_TEST_END_COMPLETE; diff --git a/subsys/bluetooth/host/hci_core.h b/subsys/bluetooth/host/hci_core.h index 458576e74f781..fb7a69539fd7b 100644 --- a/subsys/bluetooth/host/hci_core.h +++ b/subsys/bluetooth/host/hci_core.h @@ -542,6 +542,8 @@ void bt_hci_le_past_received_v2(struct net_buf *buf); void bt_hci_le_cs_read_remote_supported_capabilities_complete(struct net_buf *buf); void bt_hci_le_cs_read_remote_fae_table_complete(struct net_buf *buf); void bt_hci_le_cs_config_complete_event(struct net_buf *buf); +void bt_hci_le_cs_security_enable_complete(struct net_buf *buf); +void bt_hci_le_cs_procedure_enable_complete(struct net_buf *buf); void bt_hci_le_cs_subevent_result(struct net_buf *buf); void bt_hci_le_cs_subevent_result_continue(struct net_buf *buf); void bt_hci_le_cs_test_end_complete(struct net_buf *buf); diff --git a/subsys/bluetooth/host/shell/cs.c b/subsys/bluetooth/host/shell/cs.c index fbc55623b1474..b1f6f18aceb38 100644 --- a/subsys/bluetooth/host/shell/cs.c +++ b/subsys/bluetooth/host/shell/cs.c @@ -219,9 +219,9 @@ static int cmd_cs_test_simple(const struct shell *sh, size_t argc, char *argv[]) params.t_fcs_time = 120; params.t_pm_time = 20; params.t_sw_time = 0; - params.tone_antenna_config_selection = BT_LE_CS_TEST_TONE_ANTENNA_CONFIGURATION_INDEX_ONE; - params.initiator_snr_control = BT_LE_CS_TEST_INITIATOR_SNR_CONTROL_NOT_USED; - params.reflector_snr_control = BT_LE_CS_TEST_REFLECTOR_SNR_CONTROL_NOT_USED; + params.tone_antenna_config_selection = BT_LE_CS_TONE_ANTENNA_CONFIGURATION_INDEX_ONE; + params.initiator_snr_control = BT_LE_CS_INITIATOR_SNR_CONTROL_NOT_USED; + params.reflector_snr_control = BT_LE_CS_REFLECTOR_SNR_CONTROL_NOT_USED; params.drbg_nonce = 0x1234; params.override_config = 0; params.override_config_0.channel_map_repetition = 1; @@ -442,6 +442,255 @@ static int cmd_cs_stop_test(const struct shell *sh, size_t argc, char *argv[]) return 0; } +static int cmd_read_local_supported_capabilities(const struct shell *sh, size_t argc, char *argv[]) +{ + int err = 0; + + struct bt_conn_le_cs_capabilities params; + + err = bt_le_cs_read_local_supported_capabilities(¶ms); + + if (err) { + shell_error(sh, "bt_le_cs_read_local_supported_capabilities returned error %d", + err); + + return -ENOEXEC; + } + + shell_print( + sh, + "Local channel sounding supported capabilities:\n" + "- Num CS configurations: %d\n" + "- Max consecutive CS procedures: %d\n" + "- Num antennas supported: %d\n" + "- Max antenna paths supported: %d\n" + "- Initiator role supported: %s\n" + "- Reflector role supported: %s\n" + "- Mode 3 supported: %s\n" + "- RTT AA only supported: %s\n" + "- RTT AA only is 10ns precise: %s\n" + "- RTT AA only N: %d\n" + "- RTT sounding supported: %s\n" + "- RTT sounding is 10ns precise: %s\n" + "- RTT sounding N: %d\n" + "- RTT random payload supported: %s\n" + "- RTT random payload is 10ns precise: %s\n" + "- RTT random payload N: %d\n" + "- Phase-based NADM with sounding sequences supported: %s\n" + "- Phase-based NADM with random sequences supported: %s\n" + "- CS Sync 2M PHY supported: %s\n" + "- CS Sync 2M 2BT PHY supported: %s\n" + "- CS without transmitter FAE supported: %s\n" + "- Channel selection algorithm #3c supported: %s\n" + "- Phase-based ranging from RTT sounding sequence supported: %s\n" + "- T_IP1 times supported: 0x%04x\n" + "- T_IP2 times supported: 0x%04x\n" + "- T_FCS times supported: 0x%04x\n" + "- T_PM times supported: 0x%04x\n" + "- T_SW time supported: %d us\n" + "- TX SNR capability: 0x%02x", + params.num_config_supported, params.max_consecutive_procedures_supported, + params.num_antennas_supported, params.max_antenna_paths_supported, + params.initiator_supported ? "Yes" : "No", + params.reflector_supported ? "Yes" : "No", params.mode_3_supported ? "Yes" : "No", + params.rtt_aa_only_precision == BT_CONN_LE_CS_RTT_AA_ONLY_NOT_SUPP ? "No" : "Yes", + params.rtt_aa_only_precision == BT_CONN_LE_CS_RTT_AA_ONLY_10NS ? "Yes" : "No", + params.rtt_aa_only_n, + params.rtt_sounding_precision == BT_CONN_LE_CS_RTT_SOUNDING_NOT_SUPP ? "No" : "Yes", + params.rtt_sounding_precision == BT_CONN_LE_CS_RTT_SOUNDING_10NS ? "Yes" : "No", + params.rtt_sounding_n, + params.rtt_random_payload_precision == BT_CONN_LE_CS_RTT_RANDOM_PAYLOAD_NOT_SUPP + ? "No" + : "Yes", + params.rtt_random_payload_precision == BT_CONN_LE_CS_RTT_RANDOM_PAYLOAD_10NS ? "Yes" + : "No", + params.rtt_random_payload_n, + params.phase_based_nadm_sounding_supported ? "Yes" : "No", + params.phase_based_nadm_random_supported ? "Yes" : "No", + params.cs_sync_2m_phy_supported ? "Yes" : "No", + params.cs_sync_2m_2bt_phy_supported ? "Yes" : "No", + params.cs_without_fae_supported ? "Yes" : "No", + params.chsel_alg_3c_supported ? "Yes" : "No", + params.pbr_from_rtt_sounding_seq_supported ? "Yes" : "No", + params.t_ip1_times_supported, params.t_ip2_times_supported, + params.t_fcs_times_supported, params.t_pm_times_supported, params.t_sw_time, + params.tx_snr_capability); + + return 0; +} + +static int cmd_write_cached_remote_supported_capabilities(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; + } + + struct bt_conn_le_cs_capabilities params; + + params.num_config_supported = 1; + params.max_consecutive_procedures_supported = 0; + params.num_antennas_supported = 1; + params.max_antenna_paths_supported = 1; + params.initiator_supported = true; + params.reflector_supported = true; + params.mode_3_supported = true; + params.rtt_aa_only_precision = BT_CONN_LE_CS_RTT_AA_ONLY_10NS; + params.rtt_sounding_precision = BT_CONN_LE_CS_RTT_SOUNDING_10NS; + params.rtt_random_payload_precision = BT_CONN_LE_CS_RTT_RANDOM_PAYLOAD_10NS; + params.rtt_aa_only_n = 5; + params.rtt_sounding_n = 6; + params.rtt_random_payload_n = 7; + params.phase_based_nadm_sounding_supported = true; + params.phase_based_nadm_random_supported = true; + params.cs_sync_2m_phy_supported = true; + params.cs_sync_2m_2bt_phy_supported = true; + params.chsel_alg_3c_supported = true; + params.cs_without_fae_supported = true; + params.pbr_from_rtt_sounding_seq_supported = false; + params.t_ip1_times_supported = BT_HCI_LE_CS_T_IP1_TIME_10US_MASK; + params.t_ip2_times_supported = BT_HCI_LE_CS_T_IP2_TIME_10US_MASK; + params.t_fcs_times_supported = BT_HCI_LE_CS_T_FCS_TIME_100US_MASK; + params.t_sw_time = 0x04; + params.tx_snr_capability = BT_HCI_LE_CS_TX_SNR_CAPABILITY_18DB_MASK; + + err = bt_le_cs_write_cached_remote_supported_capabilities(default_conn, ¶ms); + + if (err) { + shell_error(sh, "bt_le_cs_set_channel_classification returned error %d", err); + return -ENOEXEC; + } + + return 0; +} + +static int cmd_security_enable(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; + } + + err = bt_le_cs_security_enable(default_conn); + + if (err) { + shell_error(sh, "bt_le_cs_security_enable returned error %d", err); + return -ENOEXEC; + } + + return 0; +} + +static int cmd_set_channel_classification(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 channel_classification[10]; + + for (int i = 0; i < 10; i++) { + channel_classification[i] = shell_strtoul(argv[1 + i], 16, &err); + + if (err) { + shell_help(sh); + shell_error(sh, "Could not parse input %d, Channel Classification[%d]", i, + i); + + return SHELL_CMD_HELP_PRINTED; + } + } + + err = bt_le_cs_set_channel_classification(channel_classification); + + if (err) { + shell_error(sh, "bt_le_cs_set_channel_classification returned error %d", err); + return -ENOEXEC; + } + + return 0; +} + +static int cmd_set_procedure_parameters(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; + } + + struct bt_le_cs_set_procedure_parameters_param params; + + params.config_id = 0; + params.max_procedure_len = 1000; + params.min_procedure_interval = 5; + params.max_procedure_interval = 5000; + params.max_procedure_count = 1; + params.min_subevent_len = 5000; + params.max_subevent_len = 4000000; + params.tone_antenna_config_selection = BT_LE_CS_TONE_ANTENNA_CONFIGURATION_INDEX_ONE; + params.phy = 0x01; + params.tx_power_delta = 0x80; + params.preferred_peer_antenna = 1; + params.snr_control_initiator = BT_LE_CS_INITIATOR_SNR_CONTROL_18dB; + params.snr_control_reflector = BT_HCI_OP_LE_CS_REFLECTOR_SNR_18; + + err = bt_le_cs_set_procedure_parameters(default_conn, ¶ms); + + if (err) { + shell_error(sh, "bt_le_cs_set_procedure_parameters returned error %d", err); + return -ENOEXEC; + } + + return 0; +} + +static int cmd_procedure_enable(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; + } + + struct bt_le_cs_procedure_enable_param params; + + params.config_id = shell_strtoul(argv[1], 16, &err); + + if (err) { + shell_help(sh); + shell_error(sh, "Could not parse input 1, Config ID"); + return SHELL_CMD_HELP_PRINTED; + } + + params.enable = shell_strtoul(argv[2], 16, &err); + + if (err) { + shell_help(sh); + shell_error(sh, "Could not parse input 2, Enable"); + return SHELL_CMD_HELP_PRINTED; + } + + err = bt_le_cs_procedure_enable(default_conn, ¶ms); + + if (err) { + shell_error(sh, "bt_le_cs_procedure_enable returned error %d", err); + return -ENOEXEC; + } + + return 0; +} + SHELL_STATIC_SUBCMD_SET_CREATE( cs_cmds, SHELL_CMD_ARG(read_remote_supported_capabilities, NULL, "", @@ -463,7 +712,20 @@ SHELL_STATIC_SUBCMD_SET_CREATE( "128b-rand] [phy-1m, phy-2m, phy-2m-2b] [chmap-rep ] [hat-shape, x-shape] " "[ch3c-jump ] [chmap ] (78-0) [chsel-3b, chsel-3c]", cmd_create_config, 4, 15), - SHELL_CMD_ARG(remove_config, NULL, "", cmd_remove_config, 2, 0), SHELL_SUBCMD_SET_END); + SHELL_CMD_ARG(remove_config, NULL, "", cmd_remove_config, 2, 0), + SHELL_CMD_ARG(read_local_supported_capabilities, NULL, "", + cmd_read_local_supported_capabilities, 1, 0), + SHELL_CMD_ARG(write_cached_remote_supported_capabilities, NULL, "", + cmd_write_cached_remote_supported_capabilities, 1, 0), + SHELL_CMD_ARG(security_enable, NULL, "", cmd_security_enable, 1, 0), + SHELL_CMD_ARG(set_channel_classification, NULL, + " " + " ", + cmd_set_channel_classification, 11, 0), + SHELL_CMD_ARG(set_procedure_parameters, NULL, "", cmd_set_procedure_parameters, 1, 0), + SHELL_CMD_ARG(procedure_enable, NULL, " ", + cmd_procedure_enable, 3, 0), + SHELL_SUBCMD_SET_END); static int cmd_cs(const struct shell *sh, size_t argc, char **argv) {