diff --git a/doc/releases/release-notes-2.3.rst b/doc/releases/release-notes-2.3.rst index c9e6ef61dd7c..88598724c76b 100644 --- a/doc/releases/release-notes-2.3.rst +++ b/doc/releases/release-notes-2.3.rst @@ -18,6 +18,30 @@ Security Vulnerability Related No security vulnerabilities received. +API Changes +*********** + +Deprecated in this release +========================== + +* Bluetooth + + * BT_LE_SCAN_FILTER_DUPLICATE, use BT_LE_SCAN_OPT_FILTER_DUPLICATE instead + * BT_LE_SCAN_FILTER_WHITELIST, use BT_LE_SCAN_OPT_FILTER_WHITELIST instead + * bt_le_scan_param::filter_dup, use bt_le_scan_param::options instead + * bt_conn_create_le(), use bt_conn_le_create() instead + * bt_conn_create_auto_le(), use bt_conn_le_create_auto() instead + * bt_conn_create_slave_le(), use bt_conn_le_create_slave() instead + * BT_LE_ADV_* macros, use BT_HCI_ADV_* macros instead + +Removed APIs in this release +============================ + + +Stable API changes in this release +================================== + + Kernel ****** diff --git a/include/bluetooth/bluetooth.h b/include/bluetooth/bluetooth.h index a7b567de2b86..02865cdd99a7 100644 --- a/include/bluetooth/bluetooth.h +++ b/include/bluetooth/bluetooth.h @@ -45,6 +45,65 @@ extern "C" { */ #define BT_ID_DEFAULT 0 +/** Opaque type representing an advertiser. */ +struct bt_le_ext_adv; + +/* Don't require everyone to include conn.h */ +struct bt_conn; + +struct bt_le_ext_adv_sent_info { + /** The number of advertising events completed. */ + u8_t num_sent; +}; + +struct bt_le_ext_adv_connected_info { + /** Connection object of the new connection */ + struct bt_conn *conn; +}; + +struct bt_le_ext_adv_scanned_info { + /** Active scanner LE address and type */ + bt_addr_le_t *addr; +}; + +struct bt_le_ext_adv_cb { + /** @brief The advertising set has finished sending adv data. + * + * This callback notifies the application that the advertising set has + * finished sending advertising data. + * The advertising set can either have been stopped by a timeout or + * because the specified number of advertising events has been reached. + * + * @param adv The advertising set object. + * @param info Information about the sent event. + */ + void (*sent)(struct bt_le_ext_adv *adv, + struct bt_le_ext_adv_sent_info *info); + + /** @brief The advertising set has accepted a new connection. + * + * This callback notifies the application that the advertising set has + * accepted a new connection. + * + * @param adv The advertising set object. + * @param info Information about the connected event. + */ + void (*connected)(struct bt_le_ext_adv *adv, + struct bt_le_ext_adv_connected_info *info); + + /** @brief The advertising set has sent scan response data. + * + * This callback notifies the application that the advertising set has + * has received a Scan Request packet, and has sent a Scan Response + * packet. + * + * @param adv The advertising set object. + * @param addr Information about the scanned event. + */ + void (*scanned)(struct bt_le_ext_adv *adv, + struct bt_le_ext_adv_scanned_info *info); +}; + /** @typedef bt_ready_cb_t * @brief Callback for notifying that Bluetooth has been enabled. * @@ -302,6 +361,74 @@ enum { /** Use whitelist to filter devices that can connect. */ BT_LE_ADV_OPT_FILTER_CONN = BIT(7), + + /** Notify the application when a scan response data has been sent to an + * active scanner. + */ + BT_LE_ADV_OPT_NOTIFY_SCAN_REQ = BIT(8), + + /** Support scan response data. + * + * When used together with @ref BT_LE_ADV_OPT_EXT_ADV then this option + * cannot be used together with the @ref BT_LE_ADV_OPT_CONNECTABLE + * option. + * When used together with @ref BT_LE_ADV_OPT_EXT_ADV then scan + * response data must be set. + */ + BT_LE_ADV_OPT_SCANNABLE = BIT(9), + + /** Advertise with extended advertising. + * + * This options enables extended advertising in the advertising set. + * In extended advertising the advertising set will send a small header + * packet on the three primary advertising channels. This small header + * points to the advertising data packet that will be sent on one of + * the 37 secondary advertising channels. + * The advertiser will send primary advertising on LE 1M PHY, and + * secondary advertising on LE 2M PHY. + * + * Without this option the advertiser will send advertising data on the + * three primary advertising channels. + * + * @note Enabling this option requires extended advertising support in + * the peer devices scanning for advertisement packets. + */ + BT_LE_ADV_OPT_EXT_ADV = BIT(10), + + /** Disable use of LE 2M PHY on the secondary advertising channel. + * + * Disabling the use of LE 2M PHY could be necessary if scanners don't + * support the LE 2M PHY. + * The advertiser will send primary advertising on LE 1M PHY, and + * secondary advertising on LE 1M PHY. + * + * @note Cannot be set if BT_LE_ADV_OPT_CODED is set. + * + * @note Requires @ref BT_LE_ADV_OPT_EXT_ADV. + */ + BT_LE_ADV_OPT_NO_2M = BIT(11), + + /** Advertise on the LE Coded PHY (Long Range). + * + * The advertiser will send both primary and secondary advertising + * on the LE Coded PHY. This gives the advertiser increased range with + * the trade-off of lower data rate and higher power consumption. + * + * @note Requires @ref BT_LE_ADV_OPT_EXT_ADV + */ + BT_LE_ADV_OPT_CODED = BIT(12), + + /** Advertise without a device address (identity or RPA). + * + * @note Requires @ref BT_LE_ADV_OPT_EXT_ADV + */ + BT_LE_ADV_OPT_ANONYMOUS = BIT(13), + + /** Advertise with transmit power. + * + * @note Requires @ref BT_LE_ADV_OPT_EXT_ADV + */ + BT_LE_ADV_OPT_USE_TX_POWER = BIT(14), }; /** LE Advertising Parameters. */ @@ -309,14 +436,27 @@ struct bt_le_adv_param { /** Local identity */ u8_t id; + /** Advertising Set Identifier, valid range 0x00 - 0x0f. + * + * @note Requires @ref BT_LE_ADV_OPT_EXT_ADV + **/ + u8_t sid; + + /** Maximum advertising events the advertiser can skip before it must + * send advertising data on the secondary advertising channel. + * + * @note Requires @ref BT_LE_ADV_OPT_EXT_ADV + */ + u8_t secondary_max_skip; + /** Bit-field of advertising options */ - u8_t options; + u32_t options; /** Minimum Advertising Interval (N * 0.625) */ - u16_t interval_min; + u32_t interval_min; /** Maximum Advertising Interval (N * 0.625) */ - u16_t interval_max; + u32_t interval_max; }; /** Helper to declare advertising parameters inline @@ -328,6 +468,8 @@ struct bt_le_adv_param { #define BT_LE_ADV_PARAM(_options, _int_min, _int_max) \ ((struct bt_le_adv_param[]) { { \ .id = BT_ID_DEFAULT, \ + .sid = 0, \ + .secondary_max_skip = 0, \ .options = (_options), \ .interval_min = (_int_min), \ .interval_max = (_int_max), \ @@ -404,6 +546,153 @@ int bt_le_adv_update_data(const struct bt_data *ad, size_t ad_len, */ int bt_le_adv_stop(void); +/** @brief Create advertising set. + * + * Create a new advertising set and set advertising parameters. + * Advertising parameters can be updated with @ref bt_le_ext_adv_update_param. + * + * @param[in] param Advertising parameters. + * @param[in] cb Callback struct to notify about advertiser activity. Can be + * NULL. Must point to valid memory during the lifetime of the + * advertising set. + * @param[out] adv Valid advertising set object on success. + * + * @return Zero on success or (negative) error code otherwise. + */ +int bt_le_ext_adv_create(const struct bt_le_adv_param *param, + const struct bt_le_ext_adv_cb *cb, + struct bt_le_ext_adv **adv); + +struct bt_le_ext_adv_start_param { + /** Advertiser timeout (N * 10 ms). + * + * Application will be notified by the advertiser sent callback. + * Set to zero for no timeout. + * + * If privacy :option:`CONFIG_BT_PRIVACY` is enabled then the timeout + * must be less than :option:`CONFIG_BT_RPA_TIMEOUT`. + */ + u16_t timeout; + /** Number of advertising events. + * + * Application will be notified by the advertiser sent callback. + * Set to zero for no limit. + */ + u8_t num_events; +}; + +/** Start advertising with the given advertising set + * + * If the advertiser is limited by either the timeout or number of advertising + * events the application will be notified by the advertiser sent callback once + * the limit is reached. + * If the advertiser is limited by both the timeout and the number of + * advertising events then the limit that is reached first will stop the + * advertiser. + * + * @param adv Advertising set object. + * @param param Advertise start parameters. + */ +int bt_le_ext_adv_start(struct bt_le_ext_adv *adv, + struct bt_le_ext_adv_start_param *param); + +/** Stop advertising with the given advertising set + * + * Stop advertising with a specific advertising set. When using this function + * the advertising sent callback will not be called. + * + * @param adv Advertising set object. + * + * @return Zero on success or (negative) error code otherwise. + */ +int bt_le_ext_adv_stop(struct bt_le_ext_adv *adv); + +/** Set an advertising set's advertising or scan response data. + * + * Set advertisement data or scan response data. If the advertising set is + * currently advertising then the advertising data will be updated in + * subsequent advertising events. + * + * If the advertising set has been configured to send advertising data on the + * primary advertising channels then the maximum data length is + * @ref BT_GAP_ADV_MAX_ADV_DATA_LEN bytes. + * If the advertising set has been configured for extended advertising, + * then the maximum data length is defined by the controller with the maximum + * possible of @ref BT_GAP_ADV_MAX_EXT_ADV_DATA_LEN bytes. + * + * @note Not all scanners support extended data length advertising data. + * + * @note When updating the advertising data while advertising the advertising + * data and scan response data length must be smaller or equal to what + * can be fit in a single advertising packet. Otherwise the + * advertiser must be stopped. + * + * @param adv Advertising set object. + * @param ad Data to be used in advertisement packets. + * @param ad_len Number of elements in ad + * @param sd Data to be used in scan response packets. + * @param sd_len Number of elements in sd + * + * @return Zero on success or (negative) error code otherwise. + */ +int bt_le_ext_adv_set_data(struct bt_le_ext_adv *adv, + const struct bt_data *ad, size_t ad_len, + const struct bt_data *sd, size_t sd_len); + +/** @brief Update advertising parameters. + * + * Update the advertising parameters. The function will return an error if the + * advertiser set is currently advertising. Stop the advertising set before + * calling this function. + * + * @param adv Advertising set object. + * @param param Advertising parameters. + * + * @return Zero on success or (negative) error code otherwise. + */ +int bt_le_ext_adv_update_param(struct bt_le_ext_adv *adv, + const struct bt_le_adv_param *param); + +/** Delete advertising set. + * + * Delete advertising set. This will free up the advertising set and make it + * possible to create a new advertising set. + * + * @return Zero on success or (negative) error code otherwise. + */ +int bt_le_ext_adv_delete(struct bt_le_ext_adv *adv); + +/** @brief Get array index of an advertising set. + * + * This function is used to map bt_adv to index of an array of + * advertising sets. The array has CONFIG_BT_EXT_ADV_MAX_ADV_SET elements. + * + * @param adv Advertising set. + * + * @return Index of the advertising set object. + * The range of the returned value is 0..CONFIG_BT_EXT_ADV_MAX_ADV_SET-1 + */ +u8_t bt_le_ext_adv_get_index(struct bt_le_ext_adv *adv); + +/** @brief Advertising set info structure. */ +struct bt_le_ext_adv_info { + /* Local identity */ + u8_t id; + + /** Currently selected Transmit Power (dBM). */ + s8_t tx_power; +}; + +/** @brief Get advertising set info + * + * @param adv Advertising set object + * @param info Advertising set info object + * + * @return Zero on success or (negative) error code on failure. + */ +int bt_le_ext_adv_get_info(const struct bt_le_ext_adv *adv, + struct bt_le_ext_adv_info *info); + /** @typedef bt_le_scan_cb_t * @brief Callback type for reporting LE scan results. * @@ -419,14 +708,28 @@ typedef void bt_le_scan_cb_t(const bt_addr_le_t *addr, s8_t rssi, u8_t adv_type, struct net_buf_simple *buf); enum { + /** Convenience value when no options are specified. */ + BT_LE_SCAN_OPT_NONE = 0, + /** Filter duplicates. */ - BT_LE_SCAN_FILTER_DUPLICATE = BIT(0), + BT_LE_SCAN_OPT_FILTER_DUPLICATE = BIT(0), /** Filter using whitelist. */ - BT_LE_SCAN_FILTER_WHITELIST = BIT(1), + BT_LE_SCAN_OPT_FILTER_WHITELIST = BIT(1), + + /** Enable scan on coded PHY (Long Range).*/ + BT_LE_SCAN_OPT_CODED = BIT(2), + + /** Disable scan on 1M phy. + * + * @note Requires @ref BT_LE_SCAN_OPT_CODED. + */ + BT_LE_SCAN_OPT_NO_1M = BIT(3), - /** Filter using extended filter policies. */ - BT_LE_SCAN_FILTER_EXTENDED = BIT(2), + BT_LE_SCAN_FILTER_DUPLICATE __deprecated = + BT_LE_SCAN_OPT_FILTER_DUPLICATE, + BT_LE_SCAN_FILTER_WHITELIST __deprecated = + BT_LE_SCAN_OPT_FILTER_WHITELIST, }; enum { @@ -442,26 +745,69 @@ struct bt_le_scan_param { /** Scan type (BT_LE_SCAN_TYPE_ACTIVE or BT_LE_SCAN_TYPE_PASSIVE) */ u8_t type; - /** Bit-field of scanning filter options. */ - u8_t filter_dup; + union { + /** Bit-field of scanning filter options. */ + u8_t filter_dup __deprecated; + + /** Bit-field of scanning options. */ + u32_t options; + }; /** Scan interval (N * 0.625 ms) */ u16_t interval; /** Scan window (N * 0.625 ms) */ u16_t window; + + /** Scan timeout (N * 10 ms) + * + * Application will be notified by the scan timeout callback. + * Set zero to disable timeout. + */ + u16_t timeout; + + /** Scan interval LE Coded PHY (N * 0.625 MS) + * + * Set zero to use same as LE 1M PHY scan interval. + */ + u16_t interval_coded; + + /** Scan window LE Coded PHY (N * 0.625 MS) + * + * Set zero to use same as LE 1M PHY scan window. + */ + u16_t window_coded; }; /** LE advertisement packet information */ struct bt_le_scan_recv_info { - /** Advertiser LE address and type */ + /** Advertiser LE address and type. + * + * If advertiser is anonymous then this address will be + * @ref BT_ADDR_LE_ANY. + */ const bt_addr_le_t *addr; - /** Strength of advertiser signal */ + /* Advertising Set Identifier. */ + u8_t sid; + + /** Strength of advertiser signal. */ s8_t rssi; - /** Advertising packet type */ + /** Transmit power of the advertiser. */ + s8_t tx_power; + + /** Advertising packet type. */ u8_t adv_type; + + /** Advertising packet properties. */ + u16_t adv_props; + + /* Primary advertising channel PHY. */ + u8_t primary_phy; + + /* Secondary advertising channel PHY. */ + u8_t secondary_phy; }; /** Listener context for (LE) scanning. */ @@ -475,6 +821,9 @@ struct bt_le_scan_cb { void (*recv)(const struct bt_le_scan_recv_info *info, struct net_buf_simple *buf); + /** @brief The scanner has stopped scanning after scan timeout. */ + void (*timeout)(void); + sys_snode_t node; }; @@ -482,21 +831,24 @@ struct bt_le_scan_cb { * * @param _type Scan Type, BT_LE_SCAN_TYPE_ACTIVE or * BT_LE_SCAN_TYPE_PASSIVE. - * @param _filter Filter options + * @param _options Scan options * @param _interval Scan Interval (N * 0.625 ms) * @param _window Scan Window (N * 0.625 ms) */ -#define BT_LE_SCAN_PARAM(_type, _filter, _interval, _window) \ +#define BT_LE_SCAN_PARAM(_type, _options, _interval, _window) \ ((struct bt_le_scan_param[]) { { \ .type = (_type), \ - .filter_dup = (_filter), \ + .options = (_options), \ .interval = (_interval), \ .window = (_window), \ + .timeout = 0, \ + .interval_coded = 0, \ + .window_coded = 0, \ } }) /** Helper macro to enable active scanning to discover new devices. */ #define BT_LE_SCAN_ACTIVE BT_LE_SCAN_PARAM(BT_LE_SCAN_TYPE_ACTIVE, \ - BT_LE_SCAN_FILTER_DUPLICATE, \ + BT_LE_SCAN_OPT_FILTER_DUPLICATE, \ BT_GAP_SCAN_FAST_INTERVAL, \ BT_GAP_SCAN_FAST_WINDOW) @@ -506,7 +858,7 @@ struct bt_le_scan_cb { * (e.g., UUID) are known to be placed in Advertising Data. */ #define BT_LE_SCAN_PASSIVE BT_LE_SCAN_PARAM(BT_LE_SCAN_TYPE_PASSIVE, \ - BT_LE_SCAN_FILTER_DUPLICATE, \ + BT_LE_SCAN_OPT_FILTER_DUPLICATE, \ BT_GAP_SCAN_FAST_INTERVAL, \ BT_GAP_SCAN_FAST_WINDOW) @@ -649,11 +1001,14 @@ struct bt_le_oob { * If privacy :option:`CONFIG_BT_PRIVACY` is enabled this will result in * generating new Resolvable Private Address (RPA) that is valid for * :option:`CONFIG_BT_RPA_TIMEOUT` seconds. This address will be used for - * advertising, active scanning and connection creation. + * advertising started by @ref bt_le_adv_start, active scanning and + * connection creation. * * @note If privacy is enabled the RPA cannot be refreshed in the following * cases: * - Creating a connection in progress, wait for the connected callback. + * In addition when extended advertising :option:`CONFIG_BT_EXT_ADV` is + * not enabled or supported by the controller: * - Advertiser is enabled using a Random Static Identity Address for a * different local identity. * - The local identity conflicts with the local identity used by other @@ -667,6 +1022,32 @@ struct bt_le_oob { */ int bt_le_oob_get_local(u8_t id, struct bt_le_oob *oob); +/** @brief Get local LE Out of Band (OOB) information. + * + * This function allows to get local information that are useful for + * Out of Band pairing or connection creation. + * + * If privacy :option:`CONFIG_BT_PRIVACY` is enabled this will result in + * generating new Resolvable Private Address (RPA) that is valid for + * :option:`CONFIG_BT_RPA_TIMEOUT` seconds. This address will be used by the + * advertising set. + * + * @note When generating OOB information for multiple advertising set all + * OOB information needs to be generated at the same time. + * + * @note If privacy is enabled the RPA cannot be refreshed in the following + * cases: + * - Creating a connection in progress, wait for the connected callback. + * + * @param[in] adv The advertising set object + * @param[out] oob LE OOB information + * + * @return Zero on success or error code otherwise, positive in case + * of protocol error or negative (POSIX) in case of stack internal error. + */ +int bt_le_ext_adv_oob_get_local(struct bt_le_ext_adv *adv, + struct bt_le_oob *oob); + /** @brief BR/EDR discovery result structure */ struct bt_br_discovery_result { /** private */ diff --git a/include/bluetooth/conn.h b/include/bluetooth/conn.h index ab3c3d3781d5..afa23629648e 100644 --- a/include/bluetooth/conn.h +++ b/include/bluetooth/conn.h @@ -22,6 +22,7 @@ #include #include #include +#include #ifdef __cplusplus extern "C" { @@ -278,6 +279,89 @@ int bt_conn_le_param_update(struct bt_conn *conn, */ int bt_conn_disconnect(struct bt_conn *conn, u8_t reason); +enum { + /** Convenience value when no options are specified. */ + BT_LE_CONN_OPT_NONE = 0, + + /** Enable LE Coded PHY. + * + * Enable scanning on the LE Coded PHY. + * Enable connection initiation on the LE Coded PHY. + */ + BT_LE_CONN_OPT_CODED = BIT(0), + + /** Enable LE 2M PHY. + * + * Enable connection initiaton on the LE 2M PHY. + */ + BT_LE_CONN_OPT_2M = BIT(1), + + /** Disable LE 1M PHY. + * + * Disable scanning on the LE 1M PHY. + * Disable connection initiation on the LE 1M PHY. + * + * @note Requires @ref BT_LE_CONN_OPT_CODED. + */ + BT_LE_CONN_OPT_NO_1M = BIT(2), +}; + +struct bt_conn_le_create_param { + + /** Bit-field of create connection options. */ + u32_t options; + + /** Scan interval (N * 0.625 ms) */ + u16_t interval; + + /** Scan window (N * 0.625 ms) */ + u16_t window; + + /** Scan interval LE Coded PHY (N * 0.625 MS) + * + * Set zero to use same as LE 1M PHY scan interval + */ + u16_t interval_coded; + + /** Scan window LE Coded PHY (N * 0.625 MS) + * + * Set zero to use same as LE 1M PHY scan window. + */ + u16_t window_coded; +}; + +/** Helper to declare create connection parameters inline + * + * @param _options Create connection options. + * @param _interval Create connection scan interval (N * 0.625 ms). + * @param _window Create connection scan window (N * 0.625 ms). + */ +#define BT_CONN_LE_CREATE_PARAM(_options, _interval, _window) \ + ((struct bt_conn_le_create_param[]) { { \ + .options = (_options), \ + .interval = (_interval), \ + .window = (_window), \ + .interval_coded = 0, \ + .window_coded = 0, \ + } }) + +/** Default LE create connection parameters. + * Scan continuously by setting scan interval equal to scan window. + */ +#define BT_CONN_LE_CREATE_CONN \ + BT_CONN_LE_CREATE_PARAM(BT_LE_CONN_OPT_NONE, \ + BT_GAP_SCAN_FAST_INTERVAL, \ + BT_GAP_SCAN_FAST_INTERVAL) + +/** Default LE create connection using whitelist parameters. + * Scan window: 30 ms. + * Scan interval: 60 ms. + */ +#define BT_CONN_LE_CREATE_CONN_AUTO \ + BT_CONN_LE_CREATE_PARAM(BT_LE_CONN_OPT_NONE, \ + BT_GAP_SCAN_FAST_INTERVAL, \ + BT_GAP_SCAN_FAST_WINDOW) + /** @brief Initiate an LE connection to a remote device. * * Allows initiate new LE link to remote peer using its address. @@ -287,13 +371,31 @@ int bt_conn_disconnect(struct bt_conn *conn, u8_t reason); * * This uses the General Connection Establishment procedure. * - * @param peer Remote address. - * @param param Initial connection parameters. + * @param[in] peer Remote address. + * @param[in] create_param Create connection parameters. + * @param[in] conn_param Initial connection parameters. + * @param[out] conn Valid connection object on success. * - * @return Valid connection object on success or NULL otherwise. + * @return Zero on success or (negative) error code on failure. */ +int bt_conn_le_create(const bt_addr_le_t *peer, + const struct bt_conn_le_create_param *create_param, + const struct bt_le_conn_param *conn_param, + struct bt_conn **conn); + +__deprecated static inline struct bt_conn *bt_conn_create_le(const bt_addr_le_t *peer, - const struct bt_le_conn_param *param); + const struct bt_le_conn_param *conn_param) +{ + struct bt_conn *conn; + + if (bt_conn_le_create(peer, BT_CONN_LE_CREATE_CONN, conn_param, + &conn)) { + return NULL; + } + + return conn; +} /** @brief Automatically connect to remote devices in whitelist. * @@ -304,12 +406,20 @@ struct bt_conn *bt_conn_create_le(const bt_addr_le_t *peer, * should be started again in the connected callback after a new connection has * been established. * - * @param param Initial connection parameters. + * @param create_param Create connection parameters + * @param conn_param Initial connection parameters. * * @return Zero on success or (negative) error code on failure. * @return -ENOMEM No free connection object available. */ -int bt_conn_create_auto_le(const struct bt_le_conn_param *param); +int bt_conn_le_create_auto(const struct bt_conn_le_create_param *create_param, + const struct bt_le_conn_param *conn_param); + +__deprecated static inline +int bt_conn_create_auto_le(const struct bt_le_conn_param *conn_param) +{ + return bt_conn_le_create_auto(BT_CONN_LE_CREATE_CONN_AUTO, conn_param); +} /** @brief Stop automatic connect creation. * @@ -351,13 +461,28 @@ int bt_le_set_auto_conn(const bt_addr_le_t *addr, * The caller gets a new reference to the connection object which must be * released with bt_conn_unref() once done using the object. * - * @param peer Remote address. - * @param param Directed advertising parameters. + * @param[in] peer Remote address. + * @param[in] param Directed advertising parameters. + * @param[out] conn Valid connection object on success. * - * @return Valid connection object on success or NULL otherwise. + * @return Zero on success or (negative) error code on failure. */ +int bt_conn_le_create_slave(const bt_addr_le_t *peer, + const struct bt_le_adv_param *param, + struct bt_conn **conn); + +__deprecated static inline struct bt_conn *bt_conn_create_slave_le(const bt_addr_le_t *peer, - const struct bt_le_adv_param *param); + const struct bt_le_adv_param *param) +{ + struct bt_conn *conn; + + if (bt_conn_le_create_slave(peer, param, &conn)) { + return NULL; + } + + return conn; +} /** Security level. */ typedef enum __packed { diff --git a/include/bluetooth/gap.h b/include/bluetooth/gap.h index e067a5329145..b4dc5da54a66 100644 --- a/include/bluetooth/gap.h +++ b/include/bluetooth/gap.h @@ -69,6 +69,60 @@ extern "C" { #define BT_GAP_INIT_CONN_INT_MIN 0x0018 /* 30 ms */ #define BT_GAP_INIT_CONN_INT_MAX 0x0028 /* 50 ms */ +/** LE PHY types */ +enum { + /** LE 1M PHY */ + BT_GAP_LE_PHY_1M = BIT(0), + /** LE 2M PHY */ + BT_GAP_LE_PHY_2M = BIT(1), + /** LE Coded PHY */ + BT_GAP_LE_PHY_CODED = BIT(2), +}; + +/* Advertising PDU types */ +enum { + /** Scannable and connectable advertising. */ + BT_GAP_ADV_TYPE_ADV_IND = 0x00, + /** Directed connectable advertising. */ + BT_GAP_ADV_TYPE_ADV_DIRECT_IND = 0x01, + /** Non-connectable and scannable advertising. */ + BT_GAP_ADV_TYPE_ADV_SCAN_IND = 0x02, + /** Non-connectable and non-scannable advertising. */ + BT_GAP_ADV_TYPE_ADV_NONCONN_IND = 0x03, + /** Additional advertising data requested by an active scanner. */ + BT_GAP_ADV_TYPE_SCAN_RSP = 0x04, + /** Extended advertising, see advertising properties. */ + BT_GAP_ADV_TYPE_EXT_ADV = 0x05, +}; + +/* Advertising PDU properties */ +enum { + /** Connectable advertising. */ + BT_GAP_ADV_PROP_CONNECTABLE = BIT(0), + /** Scannable advertising. */ + BT_GAP_ADV_PROP_SCANNABLE = BIT(1), + /** Directed advertising. */ + BT_GAP_ADV_PROP_DIRECTED = BIT(2), + /** Additional advertising data requested by an active scanner. */ + BT_GAP_ADV_PROP_SCAN_RESPONSE = BIT(3), + /** Extended advertising. */ + BT_GAP_ADV_PROP_EXT_ADV = BIT(4), +}; + +/** Maximum advertising data length. */ +#define BT_GAP_ADV_MAX_ADV_DATA_LEN 31 +/** Maximum extendend advertising data length. + * + * @note The maximum advertising data length that can be sent by an extended + * advertiser is defined by the controller. + */ +#define BT_GAP_ADV_MAX_EXT_ADV_DATA_LEN 1650 + +#define BT_GAP_TX_POWER_INVALID 0x7f +#define BT_GAP_RSSI_INVALID 0x7f +#define BT_GAP_SID_INVALID 0xff +#define BT_GAP_NO_TIMEOUT 0x0000 + #ifdef __cplusplus } #endif diff --git a/include/bluetooth/hci.h b/include/bluetooth/hci.h index d8f84a85b0cc..1fe25b50e120 100644 --- a/include/bluetooth/hci.h +++ b/include/bluetooth/hci.h @@ -27,6 +27,9 @@ extern "C" { #define BT_HCI_OWN_ADDR_RPA_OR_RANDOM 0x03 #define BT_HCI_OWN_ADDR_RPA_MASK 0x02 +#define BT_HCI_PEER_ADDR_RPA_UNRESOLVED 0xfe +#define BT_HCI_PEER_ADDR_ANONYMOUS 0xff + #define BT_ENC_KEY_SIZE_MIN 0x07 #define BT_ENC_KEY_SIZE_MAX 0x10 @@ -96,8 +99,8 @@ struct bt_hci_cmd_hdr { #define BT_LE_FEAT_BIT_SMI_TX 9 #define BT_LE_FEAT_BIT_SMI_RX 10 #define BT_LE_FEAT_BIT_PHY_CODED 11 -#define BT_LE_FEAT_BIT_ADV_EXT 12 -#define BT_LE_FEAT_BIT_ADV_PER 13 +#define BT_LE_FEAT_BIT_EXT_ADV 12 +#define BT_LE_FEAT_BIT_PER_ADV 13 #define BT_LE_FEAT_BIT_CHAN_SEL_ALGO_2 14 #define BT_LE_FEAT_BIT_PWR_CLASS_1 15 #define BT_LE_FEAT_BIT_MIN_USED_CHAN_PROC 16 @@ -138,6 +141,8 @@ struct bt_hci_cmd_hdr { BT_LE_FEAT_BIT_PHY_CODED) #define BT_FEAT_LE_PRIVACY(feat) BT_LE_FEAT_TEST(feat, \ BT_LE_FEAT_BIT_PRIVACY) +#define BT_FEAT_LE_EXT_ADV(feat) BT_LE_FEAT_TEST(feat, \ + BT_LE_FEAT_BIT_EXT_ADV) /* LE States */ #define BT_LE_STATES_SLAVE_CONN_ADV(states) (states & 0x0000004000000000) @@ -609,14 +614,21 @@ struct bt_hci_cp_le_set_random_address { bt_addr_t bdaddr; } __packed; -/* Advertising types */ -#define BT_LE_ADV_IND 0x00 -#define BT_LE_ADV_DIRECT_IND 0x01 -#define BT_LE_ADV_SCAN_IND 0x02 -#define BT_LE_ADV_NONCONN_IND 0x03 -#define BT_LE_ADV_DIRECT_IND_LOW_DUTY 0x04 -/* Needed in advertising reports when getting info about */ -#define BT_LE_ADV_SCAN_RSP 0x04 +/* LE Advertising Types (LE Advertising Parameters Set)*/ +#define BT_LE_ADV_IND (__DEPRECATED_MACRO 0x00) +#define BT_LE_ADV_DIRECT_IND (__DEPRECATED_MACRO 0x01) +#define BT_LE_ADV_SCAN_IND (__DEPRECATED_MACRO 0x02) +#define BT_LE_ADV_NONCONN_IND (__DEPRECATED_MACRO 0x03) +#define BT_LE_ADV_DIRECT_IND_LOW_DUTY (__DEPRECATED_MACRO 0x04) +/* LE Advertising PDU Types. */ +#define BT_LE_ADV_SCAN_RSP (__DEPRECATED_MACRO 0x04) + +#define BT_HCI_ADV_IND 0x00 +#define BT_HCI_ADV_DIRECT_IND 0x01 +#define BT_HCI_ADV_SCAN_IND 0x02 +#define BT_HCI_ADV_NONCONN_IND 0x03 +#define BT_HCI_ADV_DIRECT_IND_LOW_DUTY 0x04 +#define BT_HCI_ADV_SCAN_RSP 0x04 #define BT_LE_ADV_FP_NO_WHITELIST 0x00 #define BT_LE_ADV_FP_WHITELIST_SCAN_REQ 0x01 @@ -1020,6 +1032,11 @@ struct bt_hci_cp_le_set_adv_set_random_addr { #define BT_HCI_LE_ADV_PROP_ANON BIT(5) #define BT_HCI_LE_ADV_PROP_TX_POWER BIT(6) +#define BT_HCI_LE_ADV_SCAN_REQ_ENABLE 1 +#define BT_HCI_LE_ADV_SCAN_REQ_DISABLE 0 + +#define BT_HCI_LE_ADV_TX_POWER_NO_PREF 0x7F + #define BT_HCI_OP_LE_SET_EXT_ADV_PARAM BT_OP(BT_OGF_LE, 0x0036) struct bt_hci_cp_le_set_ext_adv_param { u8_t handle; @@ -1051,6 +1068,8 @@ struct bt_hci_rp_le_set_ext_adv_param { #define BT_HCI_LE_EXT_ADV_FRAG_ENABLED 0x00 #define BT_HCI_LE_EXT_ADV_FRAG_DISABLED 0x01 +#define BT_HCI_LE_EXT_ADV_FRAG_MAX_LEN 251 + #define BT_HCI_OP_LE_SET_EXT_ADV_DATA BT_OP(BT_OGF_LE, 0x0037) struct bt_hci_cp_le_set_ext_adv_data { u8_t handle; @@ -1154,8 +1173,8 @@ struct bt_hci_cp_le_set_ext_scan_enable { #define BT_HCI_OP_LE_EXT_CREATE_CONN BT_OP(BT_OGF_LE, 0x0043) struct bt_hci_ext_conn_phy { - u16_t interval; - u16_t window; + u16_t scan_interval; + u16_t scan_window; u16_t conn_interval_min; u16_t conn_interval_max; u16_t conn_latency; @@ -1585,6 +1604,18 @@ struct bt_hci_evt_le_phy_update_complete { } __packed; #define BT_HCI_EVT_LE_EXT_ADVERTISING_REPORT 0x0d + +#define BT_HCI_LE_ADV_EVT_TYPE_CONN BIT(0) +#define BT_HCI_LE_ADV_EVT_TYPE_SCAN BIT(1) +#define BT_HCI_LE_ADV_EVT_TYPE_DIRECT BIT(2) +#define BT_HCI_LE_ADV_EVT_TYPE_SCAN_RSP BIT(3) +#define BT_HCI_LE_ADV_EVT_TYPE_LEGACY BIT(4) + +#define BT_HCI_LE_ADV_EVT_TYPE_DATA_STATUS(ev_type) (((ev_type) >> 5) & 0x03) +#define BT_HCI_LE_ADV_EVT_TYPE_DATA_STATUS_COMPLETE 0 +#define BT_HCI_LE_ADV_EVT_TYPE_DATA_STATUS_PARTIAL 1 +#define BT_HCI_LE_ADV_EVT_TYPE_DATA_STATUS_INCOMPLETE 2 + struct bt_hci_evt_le_ext_advertising_info { u16_t evt_type; bt_addr_le_t addr; @@ -1633,7 +1664,7 @@ struct bt_hci_evt_le_per_adv_sync_lost { #define BT_HCI_EVT_LE_SCAN_TIMEOUT 0x11 #define BT_HCI_EVT_LE_ADV_SET_TERMINATED 0x12 -struct bt_hci_evt_le_per_adv_set_terminated { +struct bt_hci_evt_le_adv_set_terminated { u8_t status; u8_t adv_handle; u16_t conn_handle; diff --git a/samples/bluetooth/central/src/main.c b/samples/bluetooth/central/src/main.c index f3086b4701ed..9175118355ed 100644 --- a/samples/bluetooth/central/src/main.c +++ b/samples/bluetooth/central/src/main.c @@ -25,13 +25,15 @@ static void device_found(const bt_addr_le_t *addr, s8_t rssi, u8_t type, struct net_buf_simple *ad) { char addr_str[BT_ADDR_LE_STR_LEN]; + int err; if (default_conn) { return; } /* We're only interested in connectable events */ - if (type != BT_LE_ADV_IND && type != BT_LE_ADV_DIRECT_IND) { + if (type != BT_GAP_ADV_TYPE_ADV_IND && + type != BT_GAP_ADV_TYPE_ADV_DIRECT_IND) { return; } @@ -47,7 +49,11 @@ static void device_found(const bt_addr_le_t *addr, s8_t rssi, u8_t type, return; } - default_conn = bt_conn_create_le(addr, BT_LE_CONN_PARAM_DEFAULT); + err = bt_conn_le_create(addr, BT_CONN_LE_CREATE_CONN, + BT_LE_CONN_PARAM_DEFAULT, &default_conn); + if (err) { + printk("Create conn to %s failed (%u)\n", addr_str, err); + } } static void start_scan(void) diff --git a/samples/bluetooth/central_hr/src/main.c b/samples/bluetooth/central_hr/src/main.c index f3e056f6007d..fa853461abd4 100644 --- a/samples/bluetooth/central_hr/src/main.c +++ b/samples/bluetooth/central_hr/src/main.c @@ -110,6 +110,7 @@ static bool eir_found(struct bt_data *data, void *user_data) } for (i = 0; i < data->data_len; i += sizeof(u16_t)) { + struct bt_le_conn_param *param; struct bt_uuid *uuid; u16_t u16; int err; @@ -126,8 +127,13 @@ static bool eir_found(struct bt_data *data, void *user_data) continue; } - default_conn = bt_conn_create_le(addr, - BT_LE_CONN_PARAM_DEFAULT); + param = BT_LE_CONN_PARAM_DEFAULT; + err = bt_conn_le_create(addr, BT_CONN_LE_CREATE_CONN, + param, &default_conn); + if (err) { + printk("Create conn failed (err %d)\n", err); + } + return false; } } @@ -145,7 +151,8 @@ static void device_found(const bt_addr_le_t *addr, s8_t rssi, u8_t type, dev, type, ad->len, rssi); /* We're only interested in connectable events */ - if (type == BT_LE_ADV_IND || type == BT_LE_ADV_DIRECT_IND) { + if (type == BT_GAP_ADV_TYPE_ADV_IND || + type == BT_GAP_ADV_TYPE_ADV_DIRECT_IND) { bt_data_parse(ad, eir_found, (void *)addr); } } @@ -157,8 +164,8 @@ static void start_scan(void) /* Use active scanning and disable duplicate filtering to handle any * devices that might update their advertising data at runtime. */ struct bt_le_scan_param scan_param = { - .type = BT_HCI_LE_SCAN_ACTIVE, - .filter_dup = BT_HCI_LE_SCAN_FILTER_DUP_DISABLE, + .type = BT_LE_SCAN_TYPE_ACTIVE, + .options = BT_LE_SCAN_OPT_NONE, .interval = BT_GAP_SCAN_FAST_INTERVAL, .window = BT_GAP_SCAN_FAST_WINDOW, }; diff --git a/samples/bluetooth/scan_adv/src/main.c b/samples/bluetooth/scan_adv/src/main.c index 0315e3780761..3dd80c0dfae3 100644 --- a/samples/bluetooth/scan_adv/src/main.c +++ b/samples/bluetooth/scan_adv/src/main.c @@ -30,7 +30,7 @@ void main(void) { struct bt_le_scan_param scan_param = { .type = BT_HCI_LE_SCAN_PASSIVE, - .filter_dup = BT_HCI_LE_SCAN_FILTER_DUP_DISABLE, + .options = BT_LE_SCAN_OPT_NONE, .interval = 0x0010, .window = 0x0010, }; diff --git a/samples/boards/bbc_microbit/pong/src/ble.c b/samples/boards/bbc_microbit/pong/src/ble.c index f3334b8ebc7f..86985899a745 100644 --- a/samples/boards/bbc_microbit/pong/src/ble.c +++ b/samples/boards/bbc_microbit/pong/src/ble.c @@ -338,14 +338,17 @@ static bool pong_uuid_match(const u8_t *data, u8_t len) static void create_conn(const bt_addr_le_t *addr) { + int err; + if (default_conn) { return; } printk("Found matching device, initiating connection...\n"); - default_conn = bt_conn_create_le(addr, BT_LE_CONN_PARAM_DEFAULT); - if (!default_conn) { + err = bt_conn_le_create(addr, BT_CONN_LE_CREATE_CONN, + BT_LE_CONN_PARAM_DEFAULT, &default_conn); + if (err) { printk("Failed to initiate connection"); return; } @@ -357,7 +360,7 @@ static void create_conn(const bt_addr_le_t *addr) static void device_found(const bt_addr_le_t *addr, s8_t rssi, u8_t type, struct net_buf_simple *ad) { - if (type != BT_LE_ADV_IND) { + if (type != BT_GAP_ADV_TYPE_ADV_IND) { return; } diff --git a/subsys/bluetooth/Kconfig b/subsys/bluetooth/Kconfig index 8c8915915d64..113f7dc9b1e0 100644 --- a/subsys/bluetooth/Kconfig +++ b/subsys/bluetooth/Kconfig @@ -83,6 +83,36 @@ config BT_BROADCASTER endmenu +config BT_EXT_ADV + bool "Extended Advertising and Scanning support [EXPERIMENTAL]" + help + Select this to enable Extended Advertising API support. + This enables support for advertising with multiple advertising sets, + extended advertising data, and advertising on LE Coded PHY. + It enables support for receiving extended advertising data as a + scanner, including support for advertising data over the LE coded PHY. + It enables establishing connections over LE Coded PHY. + +if BT_EXT_ADV +config BT_EXT_ADV_LEGACY_SUPPORT + bool "Support starting advertising through legacy commands" + help + Select this to enable the use of the Legacy Advertising HCI commands. + This option should be used where the capabilities of the controller + is not known. + If this option is not enabled the controller must support the extended + advertising feature. + +config BT_EXT_ADV_MAX_ADV_SET + int "Maximum number of simultaneous advertising sets" + range 1 1 + default 1 + help + Maximum number of simultaneous Bluetooth advertising sets + supported. + +endif # BT_EXT_ADV + menu "Observer" visible if !BT_CENTRAL diff --git a/subsys/bluetooth/controller/hci/hci.c b/subsys/bluetooth/controller/hci/hci.c index 1e5648d8710b..1e05f27b963d 100644 --- a/subsys/bluetooth/controller/hci/hci.c +++ b/subsys/bluetooth/controller/hci/hci.c @@ -940,7 +940,7 @@ static void le_set_adv_param(struct net_buf *buf, struct net_buf **evt) min_interval = sys_le16_to_cpu(cmd->min_interval); if (IS_ENABLED(CONFIG_BT_CTLR_PARAM_CHECK) && - (cmd->type != BT_LE_ADV_DIRECT_IND)) { + (cmd->type != BT_HCI_ADV_DIRECT_IND)) { u16_t max_interval = sys_le16_to_cpu(cmd->max_interval); if ((min_interval > max_interval) || @@ -2446,7 +2446,7 @@ static inline void le_dir_adv_report(struct pdu_adv *adv, struct net_buf *buf, dir_info = (void *)(((u8_t *)drp) + sizeof(*drp)); /* Directed Advertising */ - dir_info->evt_type = BT_LE_ADV_DIRECT_IND; + dir_info->evt_type = BT_HCI_ADV_DIRECT_IND; #if defined(CONFIG_BT_CTLR_PRIVACY) if (rl_idx < ll_rl_size_get()) { diff --git a/subsys/bluetooth/host/Kconfig b/subsys/bluetooth/host/Kconfig index 1a77429abb1b..88e6c62125e0 100644 --- a/subsys/bluetooth/host/Kconfig +++ b/subsys/bluetooth/host/Kconfig @@ -34,6 +34,7 @@ config BT_RX_BUF_COUNT config BT_RX_BUF_LEN int "Maximum supported HCI RX buffer length" default 264 if BT_BREDR + default 258 if BT_EXT_ADV default 77 if BT_MESH_PROXY default 76 range 73 2000 @@ -63,7 +64,7 @@ config BT_DISCARDABLE_BUF_COUNT config BT_DISCARDABLE_BUF_SIZE int "Size of discardable event buffers" range 45 257 - default 257 if BT_BREDR + default 257 if BT_BREDR || BT_EXT_ADV default 45 help Size of buffers in the separate discardable event buffer pool. diff --git a/subsys/bluetooth/host/conn.c b/subsys/bluetooth/host/conn.c index 8eefd058ba21..f14a14a67368 100644 --- a/subsys/bluetooth/host/conn.c +++ b/subsys/bluetooth/host/conn.c @@ -1917,18 +1917,20 @@ void bt_conn_foreach(int type, void (*func)(struct bt_conn *conn, void *data), struct bt_conn *bt_conn_ref(struct bt_conn *conn) { - atomic_inc(&conn->ref); + atomic_val_t old = atomic_inc(&conn->ref); - BT_DBG("handle %u ref %u", conn->handle, atomic_get(&conn->ref)); + BT_DBG("handle %u ref %u -> %u", conn->handle, old, + atomic_get(&conn->ref)); return conn; } void bt_conn_unref(struct bt_conn *conn) { - atomic_dec(&conn->ref); + atomic_val_t old = atomic_dec(&conn->ref); - BT_DBG("handle %u ref %u", conn->handle, atomic_get(&conn->ref)); + BT_DBG("handle %u ref %u -> %u", conn->handle, old, + atomic_get(&conn->ref)); } const bt_addr_le_t *bt_conn_get_dst(const struct bt_conn *conn) @@ -2121,7 +2123,8 @@ static void bt_conn_set_param_le(struct bt_conn *conn, } #if defined(CONFIG_BT_WHITELIST) -int bt_conn_create_auto_le(const struct bt_le_conn_param *param) +int bt_conn_le_create_auto(const struct bt_conn_le_create_param *create_param, + const struct bt_le_conn_param *param) { struct bt_conn *conn; int err; @@ -2161,8 +2164,10 @@ int bt_conn_create_auto_le(const struct bt_le_conn_param *param) return -ENOMEM; } - atomic_set_bit(conn->flags, BT_CONN_AUTO_CONNECT); bt_conn_set_param_le(conn, param); + bt_dev.create_param = *create_param; + + atomic_set_bit(conn->flags, BT_CONN_AUTO_CONNECT); bt_conn_set_state(conn, BT_CONN_CONNECT_AUTO); err = bt_le_create_conn(conn); @@ -2213,30 +2218,33 @@ int bt_conn_create_auto_stop(void) } #endif /* defined(CONFIG_BT_WHITELIST) */ -struct bt_conn *bt_conn_create_le(const bt_addr_le_t *peer, - const struct bt_le_conn_param *param) +int bt_conn_le_create(const bt_addr_le_t *peer, + const struct bt_conn_le_create_param *create_param, + const struct bt_le_conn_param *conn_param, + struct bt_conn **ret_conn) { struct bt_conn *conn; bt_addr_le_t dst; + int err; if (!atomic_test_bit(bt_dev.flags, BT_DEV_READY)) { - return NULL; + return -EAGAIN; } - if (!bt_le_conn_params_valid(param)) { - return NULL; + if (!bt_le_conn_params_valid(conn_param)) { + return -EINVAL; } if (atomic_test_bit(bt_dev.flags, BT_DEV_EXPLICIT_SCAN)) { - return NULL; + return -EINVAL; } if (atomic_test_bit(bt_dev.flags, BT_DEV_INITIATING)) { - return NULL; + return -EALREADY; } if (!bt_le_scan_random_addr_check()) { - return NULL; + return -EINVAL; } conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, peer); @@ -2252,7 +2260,7 @@ struct bt_conn *bt_conn_create_le(const bt_addr_le_t *peer, BT_WARN("Found valid connection in %s state", state2str(conn->state)); bt_conn_unref(conn); - return NULL; + return -EINVAL; } if (peer->type == BT_ADDR_LE_PUBLIC_ID || @@ -2266,38 +2274,43 @@ struct bt_conn *bt_conn_create_le(const bt_addr_le_t *peer, /* Only default identity supported for now */ conn = bt_conn_add_le(BT_ID_DEFAULT, &dst); if (!conn) { - return NULL; + return -ENOMEM; } - bt_conn_set_param_le(conn, param); + bt_conn_set_param_le(conn, conn_param); + bt_dev.create_param = *create_param; #if defined(CONFIG_BT_SMP) if (!bt_dev.le.rl_size || bt_dev.le.rl_entries > bt_dev.le.rl_size) { bt_conn_set_state(conn, BT_CONN_CONNECT_SCAN); - if (bt_le_scan_update(true)) { + err = bt_le_scan_update(true); + if (err) { bt_conn_set_state(conn, BT_CONN_DISCONNECTED); bt_conn_unref(conn); - return NULL; + return err; } - return conn; + *ret_conn = conn; + return 0; } #endif bt_conn_set_state(conn, BT_CONN_CONNECT); - if (bt_le_create_conn(conn)) { + err = bt_le_create_conn(conn); + if (err) { conn->err = 0; bt_conn_set_state(conn, BT_CONN_DISCONNECTED); bt_conn_unref(conn); bt_le_scan_update(false); - return NULL; + return err; } - return conn; + *ret_conn = conn; + return 0; } #if !defined(CONFIG_BT_WHITELIST) @@ -2360,8 +2373,9 @@ int bt_le_set_auto_conn(const bt_addr_le_t *addr, #endif /* CONFIG_BT_CENTRAL */ #if defined(CONFIG_BT_PERIPHERAL) -struct bt_conn *bt_conn_create_slave_le(const bt_addr_le_t *peer, - const struct bt_le_adv_param *param) +int bt_conn_le_create_slave(const bt_addr_le_t *peer, + const struct bt_le_adv_param *param, + struct bt_conn **ret_conn) { int err; struct bt_conn *conn; @@ -2384,25 +2398,24 @@ struct bt_conn *bt_conn_create_slave_le(const bt_addr_le_t *peer, BT_WARN("Found valid connection in %s state", state2str(conn->state)); bt_conn_unref(conn); - return NULL; + return -EINVAL; } conn = bt_conn_add_le(param->id, peer); if (!conn) { - return NULL; + return -ENOMEM; } bt_conn_set_state(conn, BT_CONN_CONNECT_DIR_ADV); err = bt_le_adv_start_internal(¶m_int, NULL, 0, NULL, 0, peer); if (err) { - BT_WARN("Directed advertising could not be started: %d", err); - bt_conn_unref(conn); - return NULL; + return err; } - return conn; + *ret_conn = conn; + return 0; } #endif /* CONFIG_BT_PERIPHERAL */ diff --git a/subsys/bluetooth/host/hci_core.c b/subsys/bluetooth/host/hci_core.c index 7ca50e3da4bf..7a0c86535966 100644 --- a/subsys/bluetooth/host/hci_core.c +++ b/subsys/bluetooth/host/hci_core.c @@ -46,6 +46,11 @@ #include "crypto.h" #include "settings.h" +#if !defined(CONFIG_BT_EXT_ADV_LEGACY_SUPPORT) +#undef BT_FEAT_LE_EXT_ADV +#define BT_FEAT_LE_EXT_ADV(feat) 1 +#endif + /* Peripheral timeout to initialize Connection Parameter Update procedure */ #define CONN_UPDATE_TIMEOUT K_MSEC(CONFIG_BT_CONN_PARAM_UPDATE_TIMEOUT) #define RPA_TIMEOUT K_SECONDS(CONFIG_BT_RPA_TIMEOUT) @@ -86,7 +91,10 @@ static bt_le_scan_cb_t *scan_dev_found_cb; #if defined(CONFIG_BT_OBSERVER) static int set_le_scan_enable(u8_t enable); static sys_slist_t scan_cbs = SYS_SLIST_STATIC_INIT(&scan_cbs); +#if defined(CONFIG_BT_EXT_ADV) +static struct bt_le_ext_adv adv_pool[CONFIG_BT_EXT_ADV_MAX_ADV_SET]; #endif +#endif /* defined(CONFIG_BT_OBSERVER) */ #if defined(CONFIG_BT_HCI_VS_EVT_USER) static bt_hci_vnd_evt_cb_t *hci_vnd_evt_cb; @@ -402,7 +410,88 @@ const bt_addr_le_t *bt_lookup_id_addr(u8_t id, const bt_addr_le_t *addr) } #endif /* CONFIG_BT_OBSERVER || CONFIG_BT_CONN */ -static int set_advertise_enable(bool enable) +#if defined(CONFIG_BT_EXT_ADV) +u8_t bt_le_ext_adv_get_index(struct bt_le_ext_adv *adv) +{ + u8_t index = adv - adv_pool; + + __ASSERT(index < ARRAY_SIZE(adv_pool), "Invalid bt_adv pointer"); + return index; +} + +static struct bt_le_ext_adv *adv_new(void) +{ + struct bt_le_ext_adv *adv = NULL; + int i; + + for (i = 0; i < ARRAY_SIZE(adv_pool); i++) { + if (!atomic_test_bit(adv_pool[i].flags, BT_ADV_CREATED)) { + adv = &adv_pool[i]; + break; + } + } + + if (!adv) { + return NULL; + } + + (void)memset(adv, 0, sizeof(*adv)); + atomic_set_bit(adv_pool[i].flags, BT_ADV_CREATED); + adv->handle = i; + + return adv; +} + +static void adv_delete(struct bt_le_ext_adv *adv) +{ + atomic_clear_bit(adv->flags, BT_ADV_CREATED); +} + +static struct bt_le_ext_adv *bt_adv_lookup_handle(u8_t handle) +{ + if (handle < ARRAY_SIZE(adv_pool) && + atomic_test_bit(adv_pool[handle].flags, BT_ADV_CREATED)) { + return &adv_pool[handle]; + } + + return NULL; +} +#endif /* defined(CONFIG_BT_EXT_ADV) */ + +static struct bt_le_ext_adv *adv_new_legacy(void) +{ +#if defined(CONFIG_BT_EXT_ADV) + if (bt_dev.adv) { + return NULL; + } + + bt_dev.adv = adv_new(); + return bt_dev.adv; +#else + return &bt_dev.adv; +#endif +} + +static void adv_delete_legacy(void) +{ +#if defined(CONFIG_BT_EXT_ADV) + if (bt_dev.adv) { + atomic_clear_bit(bt_dev.adv->flags, BT_ADV_CREATED); + bt_dev.adv = NULL; + } +#endif +} + +struct bt_le_ext_adv *bt_adv_lookup_legacy(void) +{ +#if defined(CONFIG_BT_EXT_ADV) + return bt_dev.adv; +#else + return &bt_dev.adv; +#endif +} + +static int set_le_adv_enable_legacy(bool enable) { struct net_buf *buf; struct cmd_state_set state; @@ -459,6 +548,86 @@ static int set_random_address(const bt_addr_t *addr) return 0; } +static int set_le_adv_enable_ext(const struct bt_le_ext_adv *adv, + bool enable, + const struct bt_le_ext_adv_start_param *param) +{ + struct net_buf *buf; + int err; + + buf = bt_hci_cmd_create(BT_HCI_OP_LE_SET_EXT_ADV_ENABLE, 6); + if (!buf) { + return -ENOBUFS; + } + + if (enable) { + net_buf_add_u8(buf, BT_HCI_LE_ADV_ENABLE); + } else { + net_buf_add_u8(buf, BT_HCI_LE_ADV_DISABLE); + } + + net_buf_add_u8(buf, 1); + + net_buf_add_u8(buf, adv->handle); + net_buf_add_le16(buf, param ? sys_cpu_to_le16(param->timeout) : 0); + net_buf_add_u8(buf, param ? param->num_events : 0); + + err = bt_hci_cmd_send_sync(BT_HCI_OP_LE_SET_EXT_ADV_ENABLE, buf, NULL); + if (err) { + return err; + } + + atomic_set_bit_to(bt_dev.flags, BT_DEV_ADVERTISING, enable); + + return 0; +} + +static int set_le_adv_enable(struct bt_le_ext_adv *adv, bool enable) +{ + if (IS_ENABLED(CONFIG_BT_EXT_ADV) && + BT_FEAT_LE_EXT_ADV(bt_dev.le.features)) { + return set_le_adv_enable_ext(adv, enable, NULL); + } + + return set_le_adv_enable_legacy(enable); +} + +static int set_adv_random_address(struct bt_le_ext_adv *adv, + const bt_addr_t *addr) +{ + struct bt_hci_cp_le_set_adv_set_random_addr *cp; + struct net_buf *buf; + int err; + + if (!(IS_ENABLED(CONFIG_BT_EXT_ADV) && + BT_FEAT_LE_EXT_ADV(bt_dev.le.features))) { + return set_random_address(addr); + } + + BT_DBG("%s", bt_addr_str(addr)); + + buf = bt_hci_cmd_create(BT_HCI_OP_LE_SET_ADV_SET_RANDOM_ADDR, + sizeof(*cp)); + if (!buf) { + return -ENOBUFS; + } + + cp = net_buf_add(buf, sizeof(*cp)); + + cp->handle = adv->handle; + bt_addr_copy(&cp->bdaddr, addr); + + err = bt_hci_cmd_send_sync(BT_HCI_OP_LE_SET_ADV_SET_RANDOM_ADDR, buf, + NULL); + if (err) { + return err; + } + + bt_addr_copy(&adv->random_addr.a, addr); + adv->random_addr.type = BT_ADDR_LE_RANDOM; + return 0; +} + int bt_addr_from_str(const char *str, bt_addr_t *addr) { int i, j; @@ -512,7 +681,39 @@ int bt_addr_le_from_str(const char *str, const char *type, bt_addr_le_t *addr) return 0; } +static void le_rpa_invalidate(void) +{ + /* RPA must be submitted */ + atomic_clear_bit(bt_dev.flags, BT_DEV_RPA_TIMEOUT_SET); + + /* Invalidate RPA */ + if (!(IS_ENABLED(CONFIG_BT_EXT_ADV) && + atomic_test_bit(bt_dev.flags, BT_DEV_SCAN_LIMITED))) { + atomic_clear_bit(bt_dev.flags, BT_DEV_RPA_VALID); + } + +#if defined(CONFIG_BT_EXT_ADV) + struct bt_le_ext_adv *adv; + + /* TODO: handle multiple advertising set */ + adv = bt_adv_lookup_handle(0); + if (adv && !atomic_test_bit(adv->flags, BT_ADV_LIMITED)) { + atomic_clear_bit(adv->flags, BT_ADV_RPA_VALID); + } +#endif /* defined(CONFIG_BT_EXT_ADV) */ +} + #if defined(CONFIG_BT_PRIVACY) +static void le_rpa_timeout_submit(void) +{ + /* Check if RPA timer is running. */ + if (atomic_test_and_set_bit(bt_dev.flags, BT_DEV_RPA_TIMEOUT_SET)) { + return; + } + + k_delayed_work_submit(&bt_dev.rpa_update, RPA_TIMEOUT); +} + /* this function sets new RPA only if current one is no longer valid */ static int le_set_private_addr(u8_t id) { @@ -532,8 +733,53 @@ static int le_set_private_addr(u8_t id) } } - /* restart timer even if failed to set new RPA */ - k_delayed_work_submit(&bt_dev.rpa_update, RPA_TIMEOUT); + le_rpa_timeout_submit(); + return err; +} + +static int le_adv_set_private_addr(struct bt_le_ext_adv *adv) +{ + bt_addr_t rpa; + int err; + + if (!(IS_ENABLED(CONFIG_BT_EXT_ADV) && + BT_FEAT_LE_EXT_ADV(bt_dev.le.features))) { + return le_set_private_addr(adv->id); + } + + /* check if RPA is valid */ + if (atomic_test_bit(adv->flags, BT_ADV_RPA_VALID)) { + return 0; + } + + if (adv == bt_adv_lookup_legacy() && adv->id == BT_ID_DEFAULT) { + /* Make sure that a Legacy advertiser using default ID has same + * RPA address as scanner roles. + */ + err = le_set_private_addr(BT_ID_DEFAULT); + if (err) { + return err; + } + + err = set_adv_random_address(adv, &bt_dev.random_addr.a); + if (!err) { + atomic_set_bit(adv->flags, BT_ADV_RPA_VALID); + } + + return 0; + } + + err = bt_rpa_create(bt_dev.irk[adv->id], &rpa); + if (!err) { + err = set_adv_random_address(adv, &rpa); + if (!err) { + atomic_set_bit(adv->flags, BT_ADV_RPA_VALID); + } + } + + if (!atomic_test_bit(adv->flags, BT_ADV_LIMITED)) { + le_rpa_timeout_submit(); + } return err; } @@ -552,27 +798,39 @@ static int le_set_private_addr(u8_t id) return set_random_address(&nrpa); } -#endif /* defined(CONFIG_BT_PRIVACY) */ -static void le_update_private_addr(void) +static int le_adv_set_private_addr(struct bt_le_ext_adv *adv) { - bool adv_enabled = false; + bt_addr_t nrpa; int err; - /* - * we need to update rpa only if advertising is ongoing, with - * BT_DEV_KEEP_ADVERTISING flag is handled in disconnected event - */ - if (atomic_test_bit(bt_dev.flags, BT_DEV_ADVERTISING)) { - set_advertise_enable(false); - adv_enabled = true; + if (IS_ENABLED(CONFIG_BT_EXT_ADV) && + BT_FEAT_LE_EXT_ADV(bt_dev.le.features)) { + return le_set_private_addr(adv->id); } + err = bt_rand(nrpa.val, sizeof(nrpa.val)); + if (err) { + return err; + } + + nrpa.val[5] &= 0x3f; + + return set_adv_random_address(adv, &nrpa); +} +#endif /* defined(CONFIG_BT_PRIVACY) */ + +static void le_update_private_addr(void) +{ + int err; + #if defined(CONFIG_BT_OBSERVER) bool scan_enabled = false; if (atomic_test_bit(bt_dev.flags, BT_DEV_SCANNING) && - atomic_test_bit(bt_dev.flags, BT_DEV_ACTIVE_SCAN)) { + atomic_test_bit(bt_dev.flags, BT_DEV_ACTIVE_SCAN) && + !(IS_ENABLED(CONFIG_BT_EXT_ADV) && + atomic_test_bit(bt_dev.flags, BT_DEV_SCAN_LIMITED))) { set_le_scan_enable(BT_HCI_LE_SCAN_DISABLE); scan_enabled = true; } @@ -586,18 +844,67 @@ static void le_update_private_addr(void) bt_le_create_conn_cancel(); } +#if defined(CONFIG_BT_EXT_ADV) + struct bt_le_ext_adv *adv; + + if (IS_ENABLED(CONFIG_BT_OBSERVER) && + !atomic_test_bit(bt_dev.flags, BT_DEV_SCAN_LIMITED)) { + err = le_set_private_addr(BT_ID_DEFAULT); + if (err) { + BT_WARN("Failed to update RPA address (%d)", err); + return; + } + } + + /* TODO: Foreach adv set */ + adv = bt_adv_lookup_handle(0); + + if (adv && !atomic_test_bit(adv->flags, BT_ADV_LIMITED) && + !atomic_test_bit(bt_dev.flags, BT_DEV_ADVERTISING_IDENTITY)) { + bool adv_enabled = false; + + if (atomic_test_bit(bt_dev.flags, BT_DEV_ADVERTISING)) { + set_le_adv_enable_ext(adv, false, NULL); + adv_enabled = true; + } + + err = le_adv_set_private_addr(adv); + if (err) { + BT_WARN("Failed to update advertiser RPA address (%d)", + err); + } + + if (adv_enabled) { + set_le_adv_enable_ext(adv, true, NULL); + } + } +#else /* defined(CONFIG_BT_EXT_ADV) */ + bool adv_enabled = false; + + /* + * we need to update rpa only if advertising is ongoing, with + * BT_DEV_KEEP_ADVERTISING flag is handled in disconnected event + */ + if (atomic_test_bit(bt_dev.flags, BT_DEV_ADVERTISING) && + !atomic_test_bit(bt_dev.flags, BT_DEV_ADVERTISING_IDENTITY)) { + set_le_adv_enable_legacy(false); + adv_enabled = true; + } /* If both advertiser and scanner is running then the advertiser ID must * be BT_ID_DEFAULT, this will update the RPA address for both roles. */ - err = le_set_private_addr(adv_enabled ? bt_dev.adv_id : BT_ID_DEFAULT); + err = le_set_private_addr(adv_enabled ? bt_dev.adv.id : BT_ID_DEFAULT); if (err) { BT_WARN("Failed to update RPA address (%d)", err); return; } +#endif /* defined(CONFIG_BT_EXT_ADV) */ +#if !defined(CONFIG_BT_EXT_ADV) if (adv_enabled) { - set_advertise_enable(true); + set_le_adv_enable_legacy(true); } +#endif /* defined(CONFIG_BT_EXT_ADV) */ #if defined(CONFIG_BT_OBSERVER) if (scan_enabled) { @@ -622,8 +929,7 @@ static void rpa_timeout(struct k_work *work) } } - /* Invalidate RPA */ - atomic_clear_bit(bt_dev.flags, BT_DEV_RPA_VALID); + le_rpa_invalidate(); /* IF no roles using the RPA is running we can stop the RPA timer */ if (!((atomic_test_bit(bt_dev.flags, BT_DEV_ADVERTISING) && @@ -636,10 +942,16 @@ static void rpa_timeout(struct k_work *work) le_update_private_addr(); } -#endif /* defined(CONFIG_BT_PRIVACY) */ +#endif /* CONFIG_BT_PRIVACY */ bool bt_le_scan_random_addr_check(void) { + if (IS_ENABLED(CONFIG_BT_EXT_ADV) && + BT_FEAT_LE_EXT_ADV(bt_dev.le.features)) { + /* Advertiser and scanner using differend random address */ + return true; + } + /* If the advertiser is not enabled or not active there is no issue */ if (!IS_ENABLED(CONFIG_BT_BROADCASTER) || !atomic_test_bit(bt_dev.flags, BT_DEV_ADVERTISING)) { @@ -651,14 +963,15 @@ bool bt_le_scan_random_addr_check(void) * valid and only updated on RPA timeout. */ if (IS_ENABLED(CONFIG_BT_PRIVACY)) { + struct bt_le_ext_adv *adv = bt_adv_lookup_legacy(); /* Cannot start scannor or initiator if the random address is * used by the advertiser for an RPA with a different identity * or for a random static identity address. */ if ((atomic_test_bit(bt_dev.flags, BT_DEV_ADVERTISING_IDENTITY) && - bt_dev.id_addr[bt_dev.adv_id].type == BT_ADDR_LE_RANDOM) || - bt_dev.adv_id != BT_ID_DEFAULT) { + bt_dev.id_addr[adv->id].type == BT_ADDR_LE_RANDOM) || + adv->id != BT_ID_DEFAULT) { return false; } } @@ -673,6 +986,12 @@ bool bt_le_scan_random_addr_check(void) static bool bt_le_adv_random_addr_check(const struct bt_le_adv_param *param) { + if (IS_ENABLED(CONFIG_BT_EXT_ADV) && + BT_FEAT_LE_EXT_ADV(bt_dev.le.features)) { + /* Advertiser and scanner using differend random address */ + return true; + } + /* If scanner roles are not enabled or not active there is no issue. */ if (!IS_ENABLED(CONFIG_BT_OBSERVER) || !(atomic_test_bit(bt_dev.flags, BT_DEV_INITIATING) || @@ -728,11 +1047,48 @@ static bool bt_le_adv_random_addr_check(const struct bt_le_adv_param *param) #if defined(CONFIG_BT_OBSERVER) -static int set_le_scan_enable(u8_t enable) +static int set_le_ext_scan_enable(u8_t enable, u16_t duration) { - struct bt_hci_cp_le_set_scan_enable *cp; + struct bt_hci_cp_le_set_ext_scan_enable *cp; + struct cmd_state_set state; struct net_buf *buf; + int err; + + buf = bt_hci_cmd_create(BT_HCI_OP_LE_SET_EXT_SCAN_ENABLE, sizeof(*cp)); + if (!buf) { + return -ENOBUFS; + } + + cp = net_buf_add(buf, sizeof(*cp)); + + if (enable == BT_HCI_LE_SCAN_ENABLE) { + cp->filter_dup = atomic_test_bit(bt_dev.flags, + BT_DEV_SCAN_FILTER_DUP); + } else { + cp->filter_dup = BT_HCI_LE_SCAN_FILTER_DUP_DISABLE; + } + + cp->enable = enable; + cp->duration = sys_cpu_to_le16(duration); + cp->period = 0; + + cmd_state_set_init(&state, bt_dev.flags, BT_DEV_SCANNING, + enable == BT_HCI_LE_SCAN_ENABLE); + cmd(buf)->state = &state; + + err = bt_hci_cmd_send_sync(BT_HCI_OP_LE_SET_EXT_SCAN_ENABLE, buf, NULL); + if (err) { + return err; + } + + return 0; +} + +static int set_le_scan_enable_legacy(u8_t enable) +{ + struct bt_hci_cp_le_set_scan_enable *cp; struct cmd_state_set state; + struct net_buf *buf; int err; buf = bt_hci_cmd_create(BT_HCI_OP_LE_SET_SCAN_ENABLE, sizeof(*cp)); @@ -762,6 +1118,16 @@ static int set_le_scan_enable(u8_t enable) return 0; } + +static int set_le_scan_enable(u8_t enable) +{ + if (IS_ENABLED(CONFIG_BT_EXT_ADV) && + BT_FEAT_LE_EXT_ADV(bt_dev.le.features)) { + return set_le_ext_scan_enable(enable, 0); + } + + return set_le_scan_enable_legacy(enable); +} #endif /* CONFIG_BT_OBSERVER */ #if defined(CONFIG_BT_CONN) @@ -889,19 +1255,10 @@ static inline bool rpa_timeout_valid_check(void) } #if defined(CONFIG_BT_CENTRAL) -int bt_le_create_conn(const struct bt_conn *conn) +static int le_create_conn_set_random_addr(bool use_filter, u8_t *own_addr_type) { - struct bt_hci_cp_le_create_conn *cp; - struct cmd_state_set state; - bool use_filter = false; - struct net_buf *buf; - u8_t own_addr_type; int err; - if (IS_ENABLED(CONFIG_BT_WHITELIST)) { - use_filter = atomic_test_bit(conn->flags, BT_CONN_AUTO_CONNECT); - } - if (IS_ENABLED(CONFIG_BT_PRIVACY)) { if (use_filter || rpa_timeout_valid_check()) { err = le_set_private_addr(BT_ID_DEFAULT); @@ -912,14 +1269,14 @@ int bt_le_create_conn(const struct bt_conn *conn) /* Force new RPA timeout so that RPA timeout is not * triggered while direct initiator is active. */ - atomic_clear_bit(bt_dev.flags, BT_DEV_RPA_VALID); + le_rpa_invalidate(); le_update_private_addr(); } if (BT_FEAT_LE_PRIVACY(bt_dev.le.features)) { - own_addr_type = BT_HCI_OWN_ADDR_RPA_OR_RANDOM; + *own_addr_type = BT_HCI_OWN_ADDR_RPA_OR_RANDOM; } else { - own_addr_type = BT_ADDR_LE_RANDOM; + *own_addr_type = BT_ADDR_LE_RANDOM; } } else { const bt_addr_le_t *addr = &bt_dev.id_addr[BT_ID_DEFAULT]; @@ -935,7 +1292,138 @@ int bt_le_create_conn(const struct bt_conn *conn) } } - own_addr_type = addr->type; + *own_addr_type = addr->type; + } + + return 0; +} + +static void set_phy_conn_param(const struct bt_conn *conn, + struct bt_hci_ext_conn_phy *phy) +{ + phy->conn_interval_min = sys_cpu_to_le16(conn->le.interval_min); + phy->conn_interval_max = sys_cpu_to_le16(conn->le.interval_max); + phy->conn_latency = sys_cpu_to_le16(conn->le.latency); + phy->supervision_timeout = sys_cpu_to_le16(conn->le.timeout); + + phy->min_ce_len = 0; + phy->max_ce_len = 0; +} + +int bt_le_create_conn_ext(const struct bt_conn *conn) +{ + struct bt_hci_cp_le_ext_create_conn *cp; + struct bt_hci_ext_conn_phy *phy; + struct cmd_state_set state; + bool use_filter = false; + struct net_buf *buf; + u8_t own_addr_type; + u8_t num_phys; + int err; + + if (IS_ENABLED(CONFIG_BT_WHITELIST)) { + use_filter = atomic_test_bit(conn->flags, BT_CONN_AUTO_CONNECT); + } + + err = le_create_conn_set_random_addr(use_filter, &own_addr_type); + if (err) { + return err; + } + + num_phys = (!(bt_dev.create_param.options & + BT_LE_CONN_OPT_NO_1M) ? 1 : 0) + + ((bt_dev.create_param.options & + BT_LE_CONN_OPT_2M) ? 1 : 0) + + ((bt_dev.create_param.options & + BT_LE_CONN_OPT_CODED) ? 1 : 0); + + buf = bt_hci_cmd_create(BT_HCI_OP_LE_EXT_CREATE_CONN, sizeof(*cp) + + num_phys * sizeof(*phy)); + if (!buf) { + return -ENOBUFS; + } + + cp = net_buf_add(buf, sizeof(*cp)); + (void)memset(cp, 0, sizeof(*cp)); + + if (use_filter) { + /* User Initiated procedure use fast scan parameters. */ + bt_addr_le_copy(&cp->peer_addr, BT_ADDR_LE_ANY); + cp->filter_policy = BT_HCI_LE_CREATE_CONN_FP_WHITELIST; + } else { + const bt_addr_le_t *peer_addr = &conn->le.dst; + +#if defined(CONFIG_BT_SMP) + if (!bt_dev.le.rl_size || + bt_dev.le.rl_entries > bt_dev.le.rl_size) { + /* Host resolving is used, use the RPA directly. */ + peer_addr = &conn->le.resp_addr; + } +#endif + bt_addr_le_copy(&cp->peer_addr, peer_addr); + cp->filter_policy = BT_HCI_LE_CREATE_CONN_FP_DIRECT; + } + + cp->own_addr_type = own_addr_type; + cp->phys = 0; + + if (!(bt_dev.create_param.options & BT_LE_CONN_OPT_NO_1M)) { + cp->phys |= BT_HCI_LE_EXT_SCAN_PHY_1M; + phy = net_buf_add(buf, sizeof(*phy)); + phy->scan_interval = sys_cpu_to_le16( + bt_dev.create_param.interval); + phy->scan_window = sys_cpu_to_le16( + bt_dev.create_param.window); + set_phy_conn_param(conn, phy); + } + + if (bt_dev.create_param.options & BT_LE_CONN_OPT_2M) { + cp->phys |= BT_HCI_LE_EXT_SCAN_PHY_2M; + phy = net_buf_add(buf, sizeof(*phy)); + phy->scan_interval = sys_cpu_to_le16( + bt_dev.create_param.interval); + phy->scan_window = sys_cpu_to_le16( + bt_dev.create_param.window); + set_phy_conn_param(conn, phy); + } + + if (bt_dev.create_param.options & BT_LE_CONN_OPT_CODED) { + u16_t interval = bt_dev.create_param.interval_coded ? + bt_dev.create_param.interval_coded : + bt_dev.create_param.interval; + u16_t window = bt_dev.create_param.window_coded ? + bt_dev.create_param.window_coded : + bt_dev.create_param.window; + + cp->phys |= BT_HCI_LE_EXT_SCAN_PHY_CODED; + phy = net_buf_add(buf, sizeof(*phy)); + phy->scan_interval = sys_cpu_to_le16(interval); + phy->scan_window = sys_cpu_to_le16(window); + set_phy_conn_param(conn, phy); + } + + cmd_state_set_init(&state, bt_dev.flags, BT_DEV_INITIATING, true); + cmd(buf)->state = &state; + + return bt_hci_cmd_send_sync(BT_HCI_OP_LE_EXT_CREATE_CONN, buf, NULL); +} + +int bt_le_create_conn_legacy(const struct bt_conn *conn) +{ + struct bt_hci_cp_le_create_conn *cp; + struct cmd_state_set state; + bool use_filter = false; + struct net_buf *buf; + u8_t own_addr_type; + int err; + + if (IS_ENABLED(CONFIG_BT_WHITELIST)) { + use_filter = atomic_test_bit(conn->flags, BT_CONN_AUTO_CONNECT); + } + + err = le_create_conn_set_random_addr(use_filter, &own_addr_type); + if (err) { + return err; } buf = bt_hci_cmd_create(BT_HCI_OP_LE_CREATE_CONN, sizeof(*cp)); @@ -951,8 +1439,6 @@ int bt_le_create_conn(const struct bt_conn *conn) /* User Initiated procedure use fast scan parameters. */ bt_addr_le_copy(&cp->peer_addr, BT_ADDR_LE_ANY); cp->filter_policy = BT_HCI_LE_CREATE_CONN_FP_WHITELIST; - cp->scan_interval = sys_cpu_to_le16(BT_GAP_SCAN_FAST_INTERVAL); - cp->scan_window = sys_cpu_to_le16(BT_GAP_SCAN_FAST_WINDOW); } else { const bt_addr_le_t *peer_addr = &conn->le.dst; @@ -965,11 +1451,11 @@ int bt_le_create_conn(const struct bt_conn *conn) #endif bt_addr_le_copy(&cp->peer_addr, peer_addr); cp->filter_policy = BT_HCI_LE_CREATE_CONN_FP_DIRECT; - /* Interval == window for continuous scanning */ - cp->scan_interval = sys_cpu_to_le16(BT_GAP_SCAN_FAST_INTERVAL); - cp->scan_window = cp->scan_interval; } + cp->scan_interval = sys_cpu_to_le16(bt_dev.create_param.interval); + cp->scan_window = sys_cpu_to_le16(bt_dev.create_param.window); + cp->conn_interval_min = sys_cpu_to_le16(conn->le.interval_min); cp->conn_interval_max = sys_cpu_to_le16(conn->le.interval_max); cp->conn_latency = sys_cpu_to_le16(conn->le.latency); @@ -981,6 +1467,16 @@ int bt_le_create_conn(const struct bt_conn *conn) return bt_hci_cmd_send_sync(BT_HCI_OP_LE_CREATE_CONN, buf, NULL); } +int bt_le_create_conn(const struct bt_conn *conn) +{ + if (IS_ENABLED(CONFIG_BT_EXT_ADV) && + BT_FEAT_LE_EXT_ADV(bt_dev.le.features)) { + return bt_le_create_conn_ext(conn); + } + + return bt_le_create_conn_legacy(conn); +} + int bt_le_create_conn_cancel(void) { struct net_buf *buf; @@ -1202,7 +1698,7 @@ static void slave_update_conn_param(struct bt_conn *conn) } #if defined(CONFIG_BT_SMP) -static void update_pending_id(struct bt_keys *keys, void *data) +static void pending_id_update(struct bt_keys *keys, void *data) { if (keys->flags & BT_KEYS_ID_PENDING_ADD) { keys->flags &= ~BT_KEYS_ID_PENDING_ADD; @@ -1216,7 +1712,25 @@ static void update_pending_id(struct bt_keys *keys, void *data) return; } } -#endif + +static void pending_id_keys_update_set(struct bt_keys *keys, u8_t flag) +{ + atomic_set_bit(bt_dev.flags, BT_DEV_ID_PENDING); + keys->flags |= flag; +} + +static void pending_id_keys_update(void) +{ + if (atomic_test_and_clear_bit(bt_dev.flags, BT_DEV_ID_PENDING)) { + if (IS_ENABLED(CONFIG_BT_CENTRAL) && + IS_ENABLED(CONFIG_BT_PRIVACY)) { + bt_keys_foreach(BT_KEYS_ALL, pending_id_update, NULL); + } else { + bt_keys_foreach(BT_KEYS_IRK, pending_id_update, NULL); + } + } +} +#endif /* defined(CONFIG_BT_SMP) */ static struct bt_conn *find_pending_connect(u8_t role, bt_addr_le_t *peer_addr) { @@ -1239,10 +1753,16 @@ static struct bt_conn *find_pending_connect(u8_t role, bt_addr_le_t *peer_addr) } if (IS_ENABLED(CONFIG_BT_PERIPHERAL) && role == BT_HCI_ROLE_SLAVE) { - conn = bt_conn_lookup_state_le(bt_dev.adv_id, peer_addr, +#if defined(CONFIG_BT_EXT_ADV) + /* TODO: handle multiple advertising set */ + struct bt_le_ext_adv *adv = bt_adv_lookup_handle(0); +#else + struct bt_le_ext_adv *adv = bt_adv_lookup_legacy(); +#endif + conn = bt_conn_lookup_state_le(adv->id, peer_addr, BT_CONN_CONNECT_DIR_ADV); if (!conn) { - conn = bt_conn_lookup_state_le(bt_dev.adv_id, + conn = bt_conn_lookup_state_le(adv->id, BT_ADDR_LE_NONE, BT_CONN_CONNECT_ADV); } @@ -1338,14 +1858,7 @@ static void enh_conn_complete(struct bt_hci_evt_le_enh_conn_complete *evt) evt->role, bt_addr_le_str(&evt->peer_addr)); #if defined(CONFIG_BT_SMP) - if (atomic_test_and_clear_bit(bt_dev.flags, BT_DEV_ID_PENDING)) { - if (IS_ENABLED(CONFIG_BT_CENTRAL) && - IS_ENABLED(CONFIG_BT_PRIVACY)) { - bt_keys_foreach(BT_KEYS_ALL, update_pending_id, NULL); - } else { - bt_keys_foreach(BT_KEYS_IRK, update_pending_id, NULL); - } - } + pending_id_keys_update(); #endif if (evt->status) { @@ -1412,8 +1925,16 @@ static void enh_conn_complete(struct bt_hci_evt_le_enh_conn_complete *evt) bt_addr_copy(&peer_addr.a, &evt->peer_rpa); peer_addr.type = BT_ADDR_LE_RANDOM; } else { - u8_t id = evt->role == BT_HCI_ROLE_SLAVE ? bt_dev.adv_id : +#if !defined(CONFIG_BT_EXT_ADV) + u8_t id = evt->role == BT_HCI_ROLE_SLAVE ? bt_dev.adv.id : + BT_ID_DEFAULT; +#else + /* TODO: handle multiple advertising set */ + struct bt_le_ext_adv *adv = bt_adv_lookup_handle(0); + + u8_t id = evt->role == BT_HCI_ROLE_SLAVE ? adv->id : BT_ID_DEFAULT; +#endif bt_addr_le_copy(&id_addr, bt_lookup_id_addr(id, &evt->peer_addr)); @@ -1479,6 +2000,15 @@ static void enh_conn_complete(struct bt_hci_evt_le_enh_conn_complete *evt) BT_LE_STATES_SLAVE_CONN_ADV(bt_dev.le.states)) { bt_le_adv_resume(); } + + if (IS_ENABLED(CONFIG_BT_EXT_ADV) && + !atomic_test_bit(bt_dev.flags, BT_DEV_KEEP_ADVERTISING) && + !BT_FEAT_LE_EXT_ADV(bt_dev.le.features)) { + /* No advertising set terminated event, must be a + * legacy advertiser set. + */ + adv_delete_legacy(); + } } if (IS_ENABLED(CONFIG_BT_CENTRAL) && @@ -1515,6 +2045,7 @@ static void le_enh_conn_complete(struct net_buf *buf) static void le_legacy_conn_complete(struct net_buf *buf) { struct bt_hci_evt_le_conn_complete *evt = (void *)buf->data; + struct bt_le_ext_adv *adv = bt_adv_lookup_legacy(); struct bt_hci_evt_le_enh_conn_complete enh; BT_DBG("status 0x%02x role %u %s", evt->status, evt->role, @@ -1531,7 +2062,13 @@ static void le_legacy_conn_complete(struct net_buf *buf) bt_addr_le_copy(&enh.peer_addr, &evt->peer_addr); if (IS_ENABLED(CONFIG_BT_PRIVACY)) { - bt_addr_copy(&enh.local_rpa, &bt_dev.random_addr.a); + if (evt->role == BT_HCI_ROLE_SLAVE && + IS_ENABLED(CONFIG_BT_EXT_ADV) && + BT_FEAT_LE_EXT_ADV(bt_dev.le.features)) { + bt_addr_copy(&enh.local_rpa, &adv->random_addr.a); + } else { + bt_addr_copy(&enh.local_rpa, &bt_dev.random_addr.a); + } } else { bt_addr_copy(&enh.local_rpa, BT_ADDR_ANY); } @@ -1761,7 +2298,7 @@ static void le_conn_update_complete(struct net_buf *buf) #if defined(CONFIG_BT_CENTRAL) static void check_pending_conn(const bt_addr_le_t *id_addr, - const bt_addr_le_t *addr, u8_t evtype) + const bt_addr_le_t *addr, u8_t adv_props) { struct bt_conn *conn; @@ -1771,7 +2308,7 @@ static void check_pending_conn(const bt_addr_le_t *id_addr, } /* Return if event is not connectable */ - if (evtype != BT_LE_ADV_IND && evtype != BT_LE_ADV_DIRECT_IND) { + if (!(adv_props & BT_HCI_LE_ADV_EVT_TYPE_CONN)) { return; } @@ -3083,11 +3620,9 @@ static int hci_id_add(u8_t id, const bt_addr_le_t *addr, u8_t peer_irk[16]) void bt_id_add(struct bt_keys *keys) { - bool adv_enabled; -#if defined(CONFIG_BT_OBSERVER) - bool scan_enabled; -#endif /* CONFIG_BT_OBSERVER */ + struct bt_le_ext_adv *adv; struct bt_conn *conn; + bool adv_enabled; int err; BT_DBG("addr %s", bt_addr_le_str(&keys->addr)); @@ -3100,19 +3635,38 @@ void bt_id_add(struct bt_keys *keys) conn = bt_conn_lookup_state_le(BT_ID_DEFAULT, NULL, BT_CONN_CONNECT); if (conn) { - atomic_set_bit(bt_dev.flags, BT_DEV_ID_PENDING); - keys->flags |= BT_KEYS_ID_PENDING_ADD; + pending_id_keys_update_set(keys, BT_KEYS_ID_PENDING_ADD); bt_conn_unref(conn); return; } adv_enabled = atomic_test_bit(bt_dev.flags, BT_DEV_ADVERTISING); + +#if defined(CONFIG_BT_EXT_ADV) + /* TODO: Foreach adv set */ + adv = bt_adv_lookup_handle(0); + if (adv && adv_enabled && + atomic_test_bit(adv->flags, BT_ADV_LIMITED)) { + pending_id_keys_update_set(keys, BT_KEYS_ID_PENDING_ADD); + return; + } +#else + adv = bt_adv_lookup_legacy(); +#endif + +#if defined(CONFIG_BT_OBSERVER) + bool scan_enabled = atomic_test_bit(bt_dev.flags, BT_DEV_SCANNING); + + if (IS_ENABLED(CONFIG_BT_EXT_ADV) && scan_enabled && + atomic_test_bit(bt_dev.flags, BT_DEV_SCAN_LIMITED)) { + pending_id_keys_update_set(keys, BT_KEYS_ID_PENDING_ADD); + } +#endif if (adv_enabled) { - set_advertise_enable(false); + set_le_adv_enable(adv, false); } #if defined(CONFIG_BT_OBSERVER) - scan_enabled = atomic_test_bit(bt_dev.flags, BT_DEV_SCANNING); if (scan_enabled) { set_le_scan_enable(BT_HCI_LE_SCAN_DISABLE); } @@ -3177,7 +3731,7 @@ void bt_id_add(struct bt_keys *keys) #endif /* CONFIG_BT_OBSERVER */ if (adv_enabled) { - set_advertise_enable(true); + set_le_adv_enable(adv, true); } } @@ -3188,15 +3742,29 @@ static void keys_add_id(struct bt_keys *keys, void *data) } } -void bt_id_del(struct bt_keys *keys) +static int hci_id_del(const bt_addr_le_t *addr) { struct bt_hci_cp_le_rem_dev_from_rl *cp; - bool adv_enabled; -#if defined(CONFIG_BT_OBSERVER) - bool scan_enabled; -#endif /* CONFIG_BT_OBSERVER */ - struct bt_conn *conn; struct net_buf *buf; + + BT_DBG("addr %s", bt_addr_le_str(addr)); + + buf = bt_hci_cmd_create(BT_HCI_OP_LE_REM_DEV_FROM_RL, sizeof(*cp)); + if (!buf) { + return -ENOBUFS; + } + + cp = net_buf_add(buf, sizeof(*cp)); + bt_addr_le_copy(&cp->peer_id_addr, addr); + + return bt_hci_cmd_send_sync(BT_HCI_OP_LE_REM_DEV_FROM_RL, buf, NULL); +} + +void bt_id_del(struct bt_keys *keys) +{ + struct bt_le_ext_adv *adv; + struct bt_conn *conn; + bool adv_enabled; int err; BT_DBG("addr %s", bt_addr_le_str(&keys->addr)); @@ -3209,19 +3777,39 @@ void bt_id_del(struct bt_keys *keys) conn = bt_conn_lookup_state_le(BT_ID_DEFAULT, NULL, BT_CONN_CONNECT); if (conn) { - atomic_set_bit(bt_dev.flags, BT_DEV_ID_PENDING); - keys->flags |= BT_KEYS_ID_PENDING_DEL; + pending_id_keys_update_set(keys, BT_KEYS_ID_PENDING_DEL); bt_conn_unref(conn); return; } adv_enabled = atomic_test_bit(bt_dev.flags, BT_DEV_ADVERTISING); + +#if defined(CONFIG_BT_EXT_ADV) + /* TODO: Foreach adv set */ + adv = bt_adv_lookup_handle(0); + if (adv && adv_enabled && + atomic_test_bit(adv->flags, BT_ADV_LIMITED)) { + pending_id_keys_update_set(keys, BT_KEYS_ID_PENDING_DEL); + return; + } +#else + adv = bt_adv_lookup_legacy(); +#endif + +#if defined(CONFIG_BT_OBSERVER) + bool scan_enabled = atomic_test_bit(bt_dev.flags, BT_DEV_SCANNING); + + if (IS_ENABLED(CONFIG_BT_EXT_ADV) && scan_enabled && + atomic_test_bit(bt_dev.flags, BT_DEV_SCAN_LIMITED)) { + pending_id_keys_update_set(keys, BT_KEYS_ID_PENDING_DEL); + } +#endif /* CONFIG_BT_OBSERVER */ + if (adv_enabled) { - set_advertise_enable(false); + set_le_adv_enable(adv, false); } #if defined(CONFIG_BT_OBSERVER) - scan_enabled = atomic_test_bit(bt_dev.flags, BT_DEV_SCANNING); if (scan_enabled) { set_le_scan_enable(BT_HCI_LE_SCAN_DISABLE); } @@ -3245,15 +3833,7 @@ void bt_id_del(struct bt_keys *keys) goto done; } - buf = bt_hci_cmd_create(BT_HCI_OP_LE_REM_DEV_FROM_RL, sizeof(*cp)); - if (!buf) { - goto done; - } - - cp = net_buf_add(buf, sizeof(*cp)); - bt_addr_le_copy(&cp->peer_id_addr, &keys->addr); - - err = bt_hci_cmd_send_sync(BT_HCI_OP_LE_REM_DEV_FROM_RL, buf, NULL); + err = hci_id_del(&keys->addr); if (err) { BT_ERR("Failed to remove IRK from controller"); goto done; @@ -3274,7 +3854,7 @@ void bt_id_del(struct bt_keys *keys) #endif /* CONFIG_BT_OBSERVER */ if (adv_enabled) { - set_advertise_enable(true); + set_le_adv_enable(adv, true); } } @@ -3655,29 +4235,10 @@ static void hci_cmd_status(struct net_buf *buf) } #if defined(CONFIG_BT_OBSERVER) -static int start_le_scan(u8_t scan_type, u16_t interval, u16_t window) +static int le_scan_set_random_addr(bool active_scan, u8_t *own_addr_type) { - struct bt_hci_cp_le_set_scan_param set_param; - struct net_buf *buf; int err; - (void)memset(&set_param, 0, sizeof(set_param)); - - set_param.scan_type = scan_type; - - /* for the rest parameters apply default values according to - * spec 4.2, vol2, part E, 7.8.10 - */ - set_param.interval = sys_cpu_to_le16(interval); - set_param.window = sys_cpu_to_le16(window); - - if (IS_ENABLED(CONFIG_BT_WHITELIST) && - atomic_test_bit(bt_dev.flags, BT_DEV_SCAN_WL)) { - set_param.filter_policy = BT_HCI_LE_SCAN_FP_USE_WHITELIST; - } else { - set_param.filter_policy = BT_HCI_LE_SCAN_FP_NO_WHITELIST; - } - if (IS_ENABLED(CONFIG_BT_PRIVACY)) { err = le_set_private_addr(BT_ID_DEFAULT); if (err) { @@ -3685,12 +4246,12 @@ static int start_le_scan(u8_t scan_type, u16_t interval, u16_t window) } if (BT_FEAT_LE_PRIVACY(bt_dev.le.features)) { - set_param.addr_type = BT_HCI_OWN_ADDR_RPA_OR_RANDOM; + *own_addr_type = BT_HCI_OWN_ADDR_RPA_OR_RANDOM; } else { - set_param.addr_type = BT_ADDR_LE_RANDOM; + *own_addr_type = BT_ADDR_LE_RANDOM; } } else { - set_param.addr_type = bt_dev.id_addr[0].type; + *own_addr_type = bt_dev.id_addr[0].type; /* Use NRPA unless identity has been explicitly requested * (through Kconfig), or if there is no advertising ongoing. @@ -3702,9 +4263,9 @@ static int start_le_scan(u8_t scan_type, u16_t interval, u16_t window) return err; } - set_param.addr_type = BT_ADDR_LE_RANDOM; + *own_addr_type = BT_ADDR_LE_RANDOM; } else if (IS_ENABLED(CONFIG_BT_SCAN_WITH_IDENTITY) && - set_param.addr_type == BT_ADDR_LE_RANDOM) { + *own_addr_type == BT_ADDR_LE_RANDOM) { /* If scanning with Identity Address we must set the * random identity address for both active and passive * scanner in order to receive adv reports that are @@ -3717,78 +4278,203 @@ static int start_le_scan(u8_t scan_type, u16_t interval, u16_t window) } } - buf = bt_hci_cmd_create(BT_HCI_OP_LE_SET_SCAN_PARAM, sizeof(set_param)); - if (!buf) { - return -ENOBUFS; - } - - net_buf_add_mem(buf, &set_param, sizeof(set_param)); - - bt_hci_cmd_send(BT_HCI_OP_LE_SET_SCAN_PARAM, buf); - - err = set_le_scan_enable(BT_HCI_LE_SCAN_ENABLE); - if (err) { - return err; - } - - atomic_set_bit_to(bt_dev.flags, BT_DEV_ACTIVE_SCAN, - scan_type == BT_HCI_LE_SCAN_ACTIVE); - return 0; } -int bt_le_scan_update(bool fast_scan) +static int start_le_scan_ext(struct bt_hci_ext_scan_phy *phy_1m, + struct bt_hci_ext_scan_phy *phy_coded, + u16_t duration) { - if (atomic_test_bit(bt_dev.flags, BT_DEV_EXPLICIT_SCAN)) { - return 0; - } + struct bt_hci_cp_le_set_ext_scan_param *set_param; + struct net_buf *buf; + u8_t own_addr_type; + bool active_scan; + int err; - if (atomic_test_bit(bt_dev.flags, BT_DEV_SCANNING)) { - int err; + active_scan = (phy_1m && phy_1m->type == BT_HCI_LE_SCAN_ACTIVE) || + (phy_coded && phy_coded->type == BT_HCI_LE_SCAN_ACTIVE); - err = set_le_scan_enable(BT_HCI_LE_SCAN_DISABLE); - if (err) { - return err; + if (duration > 0) { + atomic_set_bit(bt_dev.flags, BT_DEV_SCAN_LIMITED); + +#if defined(CONFIG_BT_PRIVACY) + if (k_delayed_work_remaining_get(&bt_dev.rpa_update) < + (RPA_TIMEOUT - K_MSEC(500))) { + atomic_clear_bit(bt_dev.flags, BT_DEV_RPA_VALID); } +#endif /* defined(CONFIG_BT_PRIVACY) */ } - if (IS_ENABLED(CONFIG_BT_CENTRAL)) { - u16_t interval, window; - struct bt_conn *conn; + err = le_scan_set_random_addr(active_scan, &own_addr_type); + if (err) { + return err; + } - /* don't restart scan if we have pending connection */ - conn = bt_conn_lookup_state_le(BT_ID_DEFAULT, NULL, - BT_CONN_CONNECT); - if (conn) { - bt_conn_unref(conn); - return 0; - } + buf = bt_hci_cmd_create(BT_HCI_OP_LE_SET_EXT_SCAN_PARAM, + sizeof(*set_param) + + (phy_1m ? sizeof(*phy_1m) : 0) + + (phy_coded ? sizeof(*phy_coded) : 0)); + if (!buf) { + return -ENOBUFS; + } - conn = bt_conn_lookup_state_le(BT_ID_DEFAULT, NULL, - BT_CONN_CONNECT_SCAN); - if (!conn) { - return 0; - } + set_param = net_buf_add(buf, sizeof(*set_param)); + set_param->own_addr_type = own_addr_type; + set_param->phys = 0; - atomic_set_bit(bt_dev.flags, BT_DEV_SCAN_FILTER_DUP); + if (IS_ENABLED(CONFIG_BT_WHITELIST) && + atomic_test_bit(bt_dev.flags, BT_DEV_SCAN_WL)) { + set_param->filter_policy = BT_HCI_LE_SCAN_FP_USE_WHITELIST; + } else { + set_param->filter_policy = BT_HCI_LE_SCAN_FP_NO_WHITELIST; + } - bt_conn_unref(conn); + if (phy_1m) { + set_param->phys |= BT_HCI_LE_EXT_SCAN_PHY_1M; + net_buf_add_mem(buf, phy_1m, sizeof(*phy_1m)); + } - if (fast_scan) { - interval = BT_GAP_SCAN_FAST_INTERVAL; - window = BT_GAP_SCAN_FAST_WINDOW; - } else { - interval = CONFIG_BT_BACKGROUND_SCAN_INTERVAL; - window = CONFIG_BT_BACKGROUND_SCAN_WINDOW; - } + if (phy_coded) { + set_param->phys |= BT_HCI_LE_EXT_SCAN_PHY_CODED; + net_buf_add_mem(buf, phy_coded, sizeof(*phy_coded)); + } - return start_le_scan(BT_HCI_LE_SCAN_PASSIVE, interval, window); + err = bt_hci_cmd_send_sync(BT_HCI_OP_LE_SET_EXT_SCAN_PARAM, buf, NULL); + if (err) { + return err; + } + + err = set_le_ext_scan_enable(BT_HCI_LE_SCAN_ENABLE, duration); + if (err) { + return err; } + atomic_set_bit_to(bt_dev.flags, BT_DEV_ACTIVE_SCAN, active_scan); + return 0; } -void bt_data_parse(struct net_buf_simple *ad, +static int start_le_scan_legacy(u8_t scan_type, u16_t interval, u16_t window) +{ + struct bt_hci_cp_le_set_scan_param set_param; + struct net_buf *buf; + int err; + bool active_scan; + + (void)memset(&set_param, 0, sizeof(set_param)); + + set_param.scan_type = scan_type; + + /* for the rest parameters apply default values according to + * spec 4.2, vol2, part E, 7.8.10 + */ + set_param.interval = sys_cpu_to_le16(interval); + set_param.window = sys_cpu_to_le16(window); + + if (IS_ENABLED(CONFIG_BT_WHITELIST) && + atomic_test_bit(bt_dev.flags, BT_DEV_SCAN_WL)) { + set_param.filter_policy = BT_HCI_LE_SCAN_FP_USE_WHITELIST; + } else { + set_param.filter_policy = BT_HCI_LE_SCAN_FP_NO_WHITELIST; + } + + active_scan = scan_type == BT_HCI_LE_SCAN_ACTIVE; + err = le_scan_set_random_addr(active_scan, &set_param.addr_type); + if (err) { + return err; + } + + buf = bt_hci_cmd_create(BT_HCI_OP_LE_SET_SCAN_PARAM, sizeof(set_param)); + if (!buf) { + return -ENOBUFS; + } + + net_buf_add_mem(buf, &set_param, sizeof(set_param)); + + err = bt_hci_cmd_send_sync(BT_HCI_OP_LE_SET_SCAN_PARAM, buf, NULL); + if (err) { + return err; + } + + err = set_le_scan_enable(BT_HCI_LE_SCAN_ENABLE); + if (err) { + return err; + } + + atomic_set_bit_to(bt_dev.flags, BT_DEV_ACTIVE_SCAN, active_scan); + + return 0; +} + +static int start_passive_scan(bool fast_scan) +{ + u16_t interval, window; + + if (fast_scan) { + interval = BT_GAP_SCAN_FAST_INTERVAL; + window = BT_GAP_SCAN_FAST_WINDOW; + } else { + interval = CONFIG_BT_BACKGROUND_SCAN_INTERVAL; + window = CONFIG_BT_BACKGROUND_SCAN_WINDOW; + } + + if (IS_ENABLED(CONFIG_BT_EXT_ADV) && + BT_FEAT_LE_EXT_ADV(bt_dev.le.features)) { + struct bt_hci_ext_scan_phy scan; + + scan.type = BT_HCI_LE_SCAN_PASSIVE; + scan.interval = sys_cpu_to_le16(interval); + scan.window = sys_cpu_to_le16(window); + + return start_le_scan_ext(&scan, NULL, 0); + } + + return start_le_scan_legacy(BT_HCI_LE_SCAN_PASSIVE, interval, window); +} + +int bt_le_scan_update(bool fast_scan) +{ + if (atomic_test_bit(bt_dev.flags, BT_DEV_EXPLICIT_SCAN)) { + return 0; + } + + if (atomic_test_bit(bt_dev.flags, BT_DEV_SCANNING)) { + int err; + + err = set_le_scan_enable(BT_HCI_LE_SCAN_DISABLE); + if (err) { + return err; + } + } + + if (IS_ENABLED(CONFIG_BT_CENTRAL)) { + struct bt_conn *conn; + + /* don't restart scan if we have pending connection */ + conn = bt_conn_lookup_state_le(BT_ID_DEFAULT, NULL, + BT_CONN_CONNECT); + if (conn) { + bt_conn_unref(conn); + return 0; + } + + conn = bt_conn_lookup_state_le(BT_ID_DEFAULT, NULL, + BT_CONN_CONNECT_SCAN); + if (!conn) { + return 0; + } + + atomic_set_bit(bt_dev.flags, BT_DEV_SCAN_FILTER_DUP); + + bt_conn_unref(conn); + + return start_passive_scan(fast_scan); + } + + return 0; +} + +void bt_data_parse(struct net_buf_simple *ad, bool (*func)(struct bt_data *data, void *user_data), void *user_data) { @@ -3819,81 +4505,342 @@ void bt_data_parse(struct net_buf_simple *ad, } } -static void le_adv_report(struct net_buf *buf) +/* Convert Legacy adv report evt_type field to adv props */ +static u8_t get_adv_props(u8_t evt_type) +{ + switch (evt_type) { + case BT_GAP_ADV_TYPE_ADV_IND: + return BT_GAP_ADV_PROP_CONNECTABLE | + BT_GAP_ADV_PROP_SCANNABLE; + + case BT_GAP_ADV_TYPE_ADV_DIRECT_IND: + return BT_GAP_ADV_PROP_CONNECTABLE | + BT_GAP_ADV_PROP_DIRECTED; + + case BT_GAP_ADV_TYPE_ADV_SCAN_IND: + return BT_GAP_ADV_PROP_SCANNABLE; + + case BT_GAP_ADV_TYPE_ADV_NONCONN_IND: + return 0; + + /* In legacy advertising report, we don't know if the scan + * response come from a connectable advertiser, so don't + * set connectable property bit. + */ + case BT_GAP_ADV_TYPE_SCAN_RSP: + return BT_GAP_ADV_PROP_SCAN_RESPONSE | + BT_GAP_ADV_PROP_SCANNABLE; + + default: + return 0; + } +} + +static void le_adv_recv(bt_addr_le_t *addr, struct bt_le_scan_recv_info *info, + struct net_buf *buf, u8_t len) +{ + struct bt_le_scan_cb *listener; + struct net_buf_simple_state state; + bt_addr_le_t id_addr; + + BT_DBG("%s event %u, len %u, rssi %d dBm", bt_addr_le_str(addr), + info->adv_type, len, info->rssi); + + if (!IS_ENABLED(CONFIG_BT_PRIVACY) && + !IS_ENABLED(CONFIG_BT_SCAN_WITH_IDENTITY) && + atomic_test_bit(bt_dev.flags, BT_DEV_EXPLICIT_SCAN) && + (info->adv_props & BT_HCI_LE_ADV_PROP_DIRECT)) { + BT_DBG("Dropped direct adv report"); + return; + } + + if (addr->type == BT_ADDR_LE_PUBLIC_ID || + addr->type == BT_ADDR_LE_RANDOM_ID) { + bt_addr_le_copy(&id_addr, addr); + id_addr.type -= BT_ADDR_LE_PUBLIC_ID; + } else if (addr->type == BT_HCI_PEER_ADDR_ANONYMOUS) { + bt_addr_le_copy(&id_addr, BT_ADDR_LE_ANY); + } else { + bt_addr_le_copy(&id_addr, + bt_lookup_id_addr(BT_ID_DEFAULT, addr)); + } + + info->addr = &id_addr; + + if (scan_dev_found_cb) { + net_buf_simple_save(&buf->b, &state); + + buf->len = len; + scan_dev_found_cb(&id_addr, info->rssi, info->adv_type, + &buf->b); + + net_buf_simple_restore(&buf->b, &state); + } + + + SYS_SLIST_FOR_EACH_CONTAINER(&scan_cbs, listener, node) { + net_buf_simple_save(&buf->b, &state); + + buf->len = len; + listener->recv(info, &buf->b); + + net_buf_simple_restore(&buf->b, &state); + } + +#if defined(CONFIG_BT_CENTRAL) + check_pending_conn(&id_addr, addr, info->adv_props); +#endif /* CONFIG_BT_CENTRAL */ +} + +#if defined(CONFIG_BT_EXT_ADV) +static void le_scan_timeout(struct net_buf *buf) +{ + struct bt_le_scan_cb *listener; + + atomic_clear_bit(bt_dev.flags, BT_DEV_SCANNING); + atomic_clear_bit(bt_dev.flags, BT_DEV_EXPLICIT_SCAN); + + atomic_clear_bit(bt_dev.flags, BT_DEV_SCAN_LIMITED); + atomic_clear_bit(bt_dev.flags, BT_DEV_RPA_VALID); + +#if defined(CONFIG_BT_SMP) + pending_id_keys_update(); +#endif + + SYS_SLIST_FOR_EACH_CONTAINER(&scan_cbs, listener, node) { + listener->timeout(); + } +} + +/* Convert Extended adv report evt_type field into adv type */ +static u8_t get_adv_type(u8_t evt_type) +{ + switch (evt_type) { + case (BT_HCI_LE_ADV_EVT_TYPE_CONN | + BT_HCI_LE_ADV_EVT_TYPE_SCAN | + BT_HCI_LE_ADV_EVT_TYPE_LEGACY): + return BT_GAP_ADV_TYPE_ADV_IND; + + case (BT_HCI_LE_ADV_EVT_TYPE_CONN | + BT_HCI_LE_ADV_EVT_TYPE_DIRECT | + BT_HCI_LE_ADV_EVT_TYPE_LEGACY): + return BT_GAP_ADV_TYPE_ADV_DIRECT_IND; + + case (BT_HCI_LE_ADV_EVT_TYPE_SCAN | + BT_HCI_LE_ADV_EVT_TYPE_LEGACY): + return BT_GAP_ADV_TYPE_ADV_SCAN_IND; + + case BT_HCI_LE_ADV_EVT_TYPE_LEGACY: + return BT_GAP_ADV_TYPE_ADV_NONCONN_IND; + + case (BT_HCI_LE_ADV_EVT_TYPE_SCAN_RSP | + BT_HCI_LE_ADV_EVT_TYPE_CONN | + BT_HCI_LE_ADV_EVT_TYPE_SCAN | + BT_HCI_LE_ADV_EVT_TYPE_LEGACY): + case (BT_HCI_LE_ADV_EVT_TYPE_SCAN_RSP | + BT_HCI_LE_ADV_EVT_TYPE_SCAN | + BT_HCI_LE_ADV_EVT_TYPE_LEGACY): + /* Scan response from connectable or non-connectable advertiser. + */ + return BT_GAP_ADV_TYPE_SCAN_RSP; + + default: + return BT_GAP_ADV_TYPE_EXT_ADV; + } +} + +static u8_t get_phy(u8_t hci_phy) +{ + switch (hci_phy) { + case BT_HCI_LE_PHY_1M: + return BT_GAP_LE_PHY_1M; + case BT_HCI_LE_PHY_2M: + return BT_GAP_LE_PHY_2M; + case BT_HCI_LE_PHY_CODED: + return BT_GAP_LE_PHY_CODED; + default: + return 0; + } +} + +static void le_adv_ext_report(struct net_buf *buf) { u8_t num_reports = net_buf_pull_u8(buf); - struct bt_hci_evt_le_advertising_info *info; BT_DBG("Adv number of reports %u", num_reports); while (num_reports--) { - struct bt_le_scan_cb *cb; - struct net_buf_simple_state state; + struct bt_hci_evt_le_ext_advertising_info *evt; struct bt_le_scan_recv_info adv_info; - bt_addr_le_t id_addr; - s8_t rssi; - if (buf->len < sizeof(*info)) { + if (buf->len < sizeof(*evt)) { BT_ERR("Unexpected end of buffer"); break; } - info = net_buf_pull_mem(buf, sizeof(*info)); - rssi = info->data[info->length]; + evt = net_buf_pull_mem(buf, sizeof(*evt)); - if (!IS_ENABLED(CONFIG_BT_PRIVACY) && - !IS_ENABLED(CONFIG_BT_SCAN_WITH_IDENTITY) && - atomic_test_bit(bt_dev.flags, BT_DEV_EXPLICIT_SCAN) && - info->evt_type == BT_LE_ADV_DIRECT_IND) { - BT_DBG("Dropped direct adv report"); - continue; + adv_info.primary_phy = get_phy(evt->prim_phy); + adv_info.secondary_phy = get_phy(evt->sec_phy); + adv_info.tx_power = evt->tx_power; + adv_info.rssi = evt->rssi; + adv_info.sid = evt->sid; + + adv_info.adv_type = get_adv_type(evt->evt_type); + /* Convert "Legacy" property to Extended property. */ + adv_info.adv_props = evt->evt_type ^ BT_HCI_LE_ADV_PROP_LEGACY; + + le_adv_recv(&evt->addr, &adv_info, buf, evt->length); + + net_buf_pull(buf, evt->length); + } +} +#endif /* defined(CONFIG_BT_EXT_ADV) */ + +static void le_adv_report(struct net_buf *buf) +{ + u8_t num_reports = net_buf_pull_u8(buf); + struct bt_hci_evt_le_advertising_info *evt; + + BT_DBG("Adv number of reports %u", num_reports); + + while (num_reports--) { + struct bt_le_scan_recv_info adv_info; + + if (buf->len < sizeof(*evt)) { + BT_ERR("Unexpected end of buffer"); + break; } - BT_DBG("%s event %u, len %u, rssi %d dBm", - bt_addr_le_str(&info->addr), - info->evt_type, info->length, rssi); + evt = net_buf_pull_mem(buf, sizeof(*evt)); - if (info->addr.type == BT_ADDR_LE_PUBLIC_ID || - info->addr.type == BT_ADDR_LE_RANDOM_ID) { - bt_addr_le_copy(&id_addr, &info->addr); - id_addr.type -= BT_ADDR_LE_PUBLIC_ID; - } else { - bt_addr_le_copy(&id_addr, - bt_lookup_id_addr(BT_ID_DEFAULT, - &info->addr)); + adv_info.rssi = evt->data[evt->length]; + adv_info.primary_phy = BT_GAP_LE_PHY_1M; + adv_info.secondary_phy = 0; + adv_info.tx_power = BT_GAP_TX_POWER_INVALID; + adv_info.sid = BT_GAP_SID_INVALID; + + adv_info.adv_type = evt->evt_type; + adv_info.adv_props = get_adv_props(evt->evt_type); + + le_adv_recv(&evt->addr, &adv_info, buf, evt->length); + + net_buf_pull(buf, evt->length + sizeof(adv_info.rssi)); + } +} +#endif /* CONFIG_BT_OBSERVER */ + +#if defined(CONFIG_BT_EXT_ADV) +#if defined(CONFIG_BT_BROADCASTER) +static void le_adv_set_terminated(struct net_buf *buf) +{ + struct bt_hci_evt_le_adv_set_terminated *evt; + struct bt_le_ext_adv *adv; + + evt = (void *)buf->data; + adv = bt_adv_lookup_handle(evt->adv_handle); + + BT_DBG("status 0x%02x adv_handle %u conn_handle 0x%02x num %u", + evt->status, evt->adv_handle, evt->conn_handle, + evt->num_completed_ext_adv_evts); + + atomic_clear_bit(bt_dev.flags, BT_DEV_ADVERTISING); + + if (evt->status && + IS_ENABLED(CONFIG_BT_PERIPHERAL) && + atomic_test_bit(bt_dev.flags, BT_DEV_ADVERTISING_NAME)) { + struct bt_conn *conn; + + conn = bt_conn_lookup_state_le(adv->id, BT_ADDR_LE_NONE, + BT_CONN_CONNECT_ADV); + if (conn) { + bt_conn_set_state(conn, BT_CONN_DISCONNECTED); + bt_conn_unref(conn); } - adv_info.addr = &id_addr; - adv_info.adv_type = info->evt_type; - adv_info.rssi = rssi; + conn = bt_conn_lookup_state_le(adv->id, NULL, + BT_CONN_CONNECT_DIR_ADV); + if (conn) { + bt_conn_set_state(conn, BT_CONN_DISCONNECTED); + bt_conn_unref(conn); + } + } + + if (!adv) { + BT_ERR("No valid adv"); + return; + } + + if (atomic_test_and_clear_bit(adv->flags, BT_ADV_LIMITED)) { + atomic_clear_bit(adv->flags, BT_ADV_RPA_VALID); - if (scan_dev_found_cb) { - net_buf_simple_save(&buf->b, &state); +#if defined(CONFIG_BT_SMP) + pending_id_keys_update(); +#endif - buf->len = info->length; - scan_dev_found_cb(&id_addr, rssi, info->evt_type, - &buf->b); + if (adv->cb && adv->cb->sent) { + struct bt_le_ext_adv_sent_info info = { + .num_sent = evt->num_completed_ext_adv_evts, + }; - net_buf_simple_restore(&buf->b, &state); + adv->cb->sent(adv, &info); } + } + + if (!evt->status && adv->cb && adv->cb->connected) { + struct bt_conn *conn = bt_conn_lookup_handle(evt->conn_handle); - SYS_SLIST_FOR_EACH_CONTAINER(&scan_cbs, cb, node) { - net_buf_simple_save(&buf->b, &state); + if (conn) { + struct bt_le_ext_adv_connected_info info = { + .conn = conn, + }; - buf->len = info->length; - cb->recv(&adv_info, &buf->b); + adv->cb->connected(adv, &info); - net_buf_simple_restore(&buf->b, &state); + bt_conn_unref(conn); } + } -#if defined(CONFIG_BT_CENTRAL) - check_pending_conn(&id_addr, &info->addr, info->evt_type); -#endif /* CONFIG_BT_CENTRAL */ + if (!atomic_test_bit(bt_dev.flags, BT_DEV_KEEP_ADVERTISING) && + adv == bt_dev.adv) { + adv_delete_legacy(); + } +} + +static void le_scan_req_received(struct net_buf *buf) +{ + struct bt_hci_evt_le_scan_req_received *evt; + struct bt_le_ext_adv *adv; + + evt = (void *)buf->data; + adv = bt_adv_lookup_handle(evt->handle); - net_buf_pull(buf, info->length + sizeof(rssi)); + BT_DBG("handle %u peer %s", evt->handle, bt_addr_le_str(&evt->addr)); + + if (!adv) { + BT_ERR("No valid adv"); + return; + } + + if (adv->cb && adv->cb->scanned) { + struct bt_le_ext_adv_scanned_info info; + bt_addr_le_t id_addr; + + if (evt->addr.type == BT_ADDR_LE_PUBLIC_ID || + evt->addr.type == BT_ADDR_LE_RANDOM_ID) { + bt_addr_le_copy(&id_addr, &evt->addr); + id_addr.type -= BT_ADDR_LE_PUBLIC_ID; + } else { + bt_addr_le_copy(&id_addr, + bt_lookup_id_addr(adv->id, &evt->addr)); + } + + info.addr = &id_addr; + adv->cb->scanned(adv, &info); } } -#endif /* CONFIG_BT_OBSERVER */ +#endif /* defined(CONFIG_BT_BROADCASTER) */ +#endif /* defined(CONFIG_BT_EXT_ADV) */ int bt_hci_get_conn_handle(const struct bt_conn *conn, u16_t *conn_handle) { @@ -3974,6 +4921,20 @@ static const struct event_handler meta_events[] = { EVENT_HANDLER(BT_HCI_EVT_LE_GENERATE_DHKEY_COMPLETE, le_dhkey_complete, sizeof(struct bt_hci_evt_le_generate_dhkey_complete)), #endif /* CONFIG_BT_SMP */ +#if defined(CONFIG_BT_EXT_ADV) +#if defined(CONFIG_BT_BROADCASTER) + EVENT_HANDLER(BT_HCI_EVT_LE_ADV_SET_TERMINATED, le_adv_set_terminated, + sizeof(struct bt_hci_evt_le_adv_set_terminated)), + EVENT_HANDLER(BT_HCI_EVT_LE_SCAN_REQ_RECEIVED, le_scan_req_received, + sizeof(struct bt_hci_evt_le_scan_req_received)), +#endif +#if defined(CONFIG_BT_OBSERVER) + EVENT_HANDLER(BT_HCI_EVT_LE_SCAN_TIMEOUT, le_scan_timeout, + 0), + EVENT_HANDLER(BT_HCI_EVT_LE_EXT_ADVERTISING_REPORT, le_adv_ext_report, + sizeof(struct bt_hci_evt_le_ext_advertising_report)), +#endif /* defined(CONFIG_BT_OBSERVER) */ +#endif /* defined(CONFIG_BT_EXT_ADV) */ }; static void hci_le_meta_event(struct net_buf *buf) @@ -4389,7 +5350,15 @@ static int le_set_event_mask(void) mask |= BT_EVT_MASK_LE_ADVERTISING_REPORT; - if (IS_ENABLED(CONFIG_BT_CONN)) { + if (IS_ENABLED(CONFIG_BT_EXT_ADV) && + BT_FEAT_LE_EXT_ADV(bt_dev.le.features)) { + mask |= BT_EVT_MASK_LE_ADV_SET_TERMINATED; + mask |= BT_EVT_MASK_LE_SCAN_REQ_RECEIVED; + mask |= BT_EVT_MASK_LE_EXT_ADVERTISING_REPORT; + mask |= BT_EVT_MASK_LE_SCAN_TIMEOUT; + } + + if (IS_ENABLED(CONFIG_BT_CONN)) { if (IS_ENABLED(CONFIG_BT_SMP) && BT_FEAT_LE_PRIVACY(bt_dev.le.features)) { mask |= BT_EVT_MASK_LE_ENH_CONN_COMPLETE; @@ -5400,11 +6369,47 @@ struct bt_ad { size_t len; }; -static int set_ad(u16_t hci_op, const struct bt_ad *ad, size_t ad_len) +static int set_data_add(u8_t *set_data, u8_t set_data_len_max, + const struct bt_ad *ad, size_t ad_len, u8_t *data_len) +{ + u8_t set_data_len = 0; + + for (size_t i = 0; i < ad_len; i++) { + const struct bt_data *data = ad[i].data; + + for (size_t j = 0; j < ad[i].len; j++) { + size_t len = data[j].data_len; + u8_t type = data[j].type; + + /* Check if ad fit in the remaining buffer */ + if ((set_data_len + len + 2) > set_data_len_max) { + len = set_data_len_max - (set_data_len + 2); + + if (type != BT_DATA_NAME_COMPLETE || !len) { + BT_ERR("Too big advertising data"); + return -EINVAL; + } + + type = BT_DATA_NAME_SHORTENED; + } + + set_data[set_data_len++] = len + 1; + set_data[set_data_len++] = type; + + memcpy(&set_data[set_data_len], data[j].data, len); + set_data_len += len; + } + } + + *data_len = set_data_len; + return 0; +} + +static int hci_set_ad(u16_t hci_op, const struct bt_ad *ad, size_t ad_len) { struct bt_hci_cp_le_set_adv_data *set_data; struct net_buf *buf; - int c, i; + int err; buf = bt_hci_cmd_create(hci_op, sizeof(*set_data)); if (!buf) { @@ -5412,42 +6417,76 @@ static int set_ad(u16_t hci_op, const struct bt_ad *ad, size_t ad_len) } set_data = net_buf_add(buf, sizeof(*set_data)); - (void)memset(set_data, 0, sizeof(*set_data)); - for (c = 0; c < ad_len; c++) { - const struct bt_data *data = ad[c].data; + err = set_data_add(set_data->data, BT_GAP_ADV_MAX_ADV_DATA_LEN, + ad, ad_len, &set_data->len); + if (err) { + net_buf_unref(buf); + return err; + } - for (i = 0; i < ad[c].len; i++) { - int len = data[i].data_len; - u8_t type = data[i].type; + return bt_hci_cmd_send_sync(hci_op, buf, NULL); +} - /* Check if ad fit in the remaining buffer */ - if (set_data->len + len + 2 > 31) { - len = 31 - (set_data->len + 2); - if (type != BT_DATA_NAME_COMPLETE || !len) { - net_buf_unref(buf); - BT_ERR("Too big advertising data"); - return -EINVAL; - } - type = BT_DATA_NAME_SHORTENED; - } +/* Set legacy data using Extended Advertising HCI commands */ +static int hci_set_ad_ext(struct bt_le_ext_adv *adv, u16_t hci_op, + const struct bt_ad *ad, size_t ad_len) +{ + struct bt_hci_cp_le_set_ext_adv_data *set_data; + struct net_buf *buf; + int err; + + buf = bt_hci_cmd_create(hci_op, sizeof(*set_data)); + if (!buf) { + return -ENOBUFS; + } - set_data->data[set_data->len++] = len + 1; - set_data->data[set_data->len++] = type; + set_data = net_buf_add(buf, sizeof(*set_data)); + (void)memset(set_data, 0, sizeof(*set_data)); - memcpy(&set_data->data[set_data->len], data[i].data, - len); - set_data->len += len; - } + err = set_data_add(set_data->data, BT_HCI_LE_EXT_ADV_FRAG_MAX_LEN, + ad, ad_len, &set_data->len); + if (err) { + net_buf_unref(buf); + return err; } + set_data->handle = adv->handle; + set_data->op = BT_HCI_LE_EXT_ADV_OP_COMPLETE_DATA; + set_data->frag_pref = BT_HCI_LE_EXT_ADV_FRAG_DISABLED; + return bt_hci_cmd_send_sync(hci_op, buf, NULL); } +static int set_ad(struct bt_le_ext_adv *adv, const struct bt_ad *ad, + size_t ad_len) +{ + if (IS_ENABLED(CONFIG_BT_EXT_ADV) && + BT_FEAT_LE_EXT_ADV(bt_dev.le.features)) { + return hci_set_ad_ext(adv, BT_HCI_OP_LE_SET_EXT_ADV_DATA, + ad, ad_len); + } + + return hci_set_ad(BT_HCI_OP_LE_SET_ADV_DATA, ad, ad_len); +} + +static int set_sd(struct bt_le_ext_adv *adv, const struct bt_ad *sd, + size_t sd_len) +{ + if (IS_ENABLED(CONFIG_BT_EXT_ADV) && + BT_FEAT_LE_EXT_ADV(bt_dev.le.features)) { + return hci_set_ad_ext(adv, BT_HCI_OP_LE_SET_EXT_SCAN_RSP_DATA, + sd, sd_len); + } + + return hci_set_ad(BT_HCI_OP_LE_SET_SCAN_RSP_DATA, sd, sd_len); +} + int bt_set_name(const char *name) { #if defined(CONFIG_BT_DEVICE_NAME_DYNAMIC) + struct bt_le_ext_adv *adv = bt_adv_lookup_legacy(); size_t len = strlen(name); int err; @@ -5462,12 +6501,12 @@ int bt_set_name(const char *name) strncpy(bt_dev.name, name, sizeof(bt_dev.name)); /* Update advertising name if in use */ - if (atomic_test_bit(bt_dev.flags, BT_DEV_ADVERTISING_NAME)) { + if (adv && atomic_test_bit(bt_dev.flags, BT_DEV_ADVERTISING_NAME)) { struct bt_data data[] = { BT_DATA(BT_DATA_NAME_COMPLETE, name, strlen(name)) }; struct bt_ad sd = { data, ARRAY_SIZE(data) }; - set_ad(BT_HCI_OP_LE_SET_SCAN_RSP_DATA, &sd, 1); + set_sd(adv, &sd, 1); } if (IS_ENABLED(CONFIG_BT_SETTINGS)) { @@ -5622,10 +6661,20 @@ int bt_id_reset(u8_t id, bt_addr_le_t *addr, u8_t *irk) return -EINVAL; } - if (id == bt_dev.adv_id && atomic_test_bit(bt_dev.flags, +#if !defined(CONFIG_BT_EXT_ADV) + if (id == bt_dev.adv.id && atomic_test_bit(bt_dev.flags, BT_DEV_ADVERTISING)) { return -EBUSY; } +#else + /* TODO: handle multiple advertising set */ + struct bt_le_ext_adv *adv = bt_adv_lookup_handle(0); + + if (adv && adv->id == id && atomic_test_bit(bt_dev.flags, + BT_DEV_ADVERTISING)) { + return -EBUSY; + } +#endif if (IS_ENABLED(CONFIG_BT_CONN) && bt_addr_le_cmp(&bt_dev.id_addr[id], BT_ADDR_LE_ANY)) { @@ -5652,10 +6701,20 @@ int bt_id_delete(u8_t id) return -EALREADY; } - if (id == bt_dev.adv_id && atomic_test_bit(bt_dev.flags, +#if !defined(CONFIG_BT_EXT_ADV) + if (id == bt_dev.adv.id && atomic_test_bit(bt_dev.flags, BT_DEV_ADVERTISING)) { return -EBUSY; } +#else + /* TODO: handle multiple advertising set */ + struct bt_le_ext_adv *adv = bt_adv_lookup_handle(0); + + if (adv && adv->id == id && atomic_test_bit(bt_dev.flags, + BT_DEV_ADVERTISING)) { + return -EBUSY; + } +#endif if (IS_ENABLED(CONFIG_BT_CONN)) { int err; @@ -5899,7 +6958,8 @@ static inline bool ad_has_name(const struct bt_data *ad, size_t ad_len) return false; } -static int le_adv_update(const struct bt_data *ad, size_t ad_len, +static int le_adv_update(struct bt_le_ext_adv *adv, + const struct bt_data *ad, size_t ad_len, const struct bt_data *sd, size_t sd_len, bool connectable, bool use_name) { @@ -5910,7 +6970,7 @@ static int le_adv_update(const struct bt_data *ad, size_t ad_len, d[0].data = ad; d[0].len = ad_len; - err = set_ad(BT_HCI_OP_LE_SET_ADV_DATA, d, 1); + err = set_ad(adv, d, 1); if (err) { return err; } @@ -5944,12 +7004,12 @@ static int le_adv_update(const struct bt_data *ad, size_t ad_len, * If any data was not provided but we enable connectable * undirected advertising sd needs to be cleared from values set * by previous calls. - * Clearing sd is done by calling set_ad() with NULL data and + * Clearing sd is done by calling set_sd() with NULL data and * zero len. * So following condition check is unusual but correct. */ if (d[0].data || d[1].data || connectable) { - err = set_ad(BT_HCI_OP_LE_SET_SCAN_RSP_DATA, d, 2); + err = set_sd(adv, d, 2); if (err) { return err; } @@ -5961,8 +7021,13 @@ static int le_adv_update(const struct bt_data *ad, size_t ad_len, int bt_le_adv_update_data(const struct bt_data *ad, size_t ad_len, const struct bt_data *sd, size_t sd_len) { + struct bt_le_ext_adv *adv = bt_adv_lookup_legacy(); bool connectable, use_name; + if (!adv) { + return -EINVAL; + } + if (!atomic_test_bit(bt_dev.flags, BT_DEV_ADVERTISING)) { return -EAGAIN; } @@ -5971,79 +7036,47 @@ int bt_le_adv_update_data(const struct bt_data *ad, size_t ad_len, BT_DEV_ADVERTISING_CONNECTABLE); use_name = atomic_test_bit(bt_dev.flags, BT_DEV_ADVERTISING_NAME); - return le_adv_update(ad, ad_len, sd, sd_len, connectable, use_name); + return le_adv_update(adv, ad, ad_len, sd, sd_len, connectable, + use_name); } -int bt_le_adv_start_internal(const struct bt_le_adv_param *param, - const struct bt_data *ad, size_t ad_len, - const struct bt_data *sd, size_t sd_len, - const bt_addr_le_t *peer) +static u8_t get_filter_policy(u8_t options) { - struct bt_hci_cp_le_set_adv_param set_param; - const bt_addr_le_t *id_addr; - struct bt_conn *conn = NULL; - struct net_buf *buf; - bool dir_adv = (peer != NULL); - int err = 0; - - if (!atomic_test_bit(bt_dev.flags, BT_DEV_READY)) { - return -EAGAIN; - } - - if (!valid_adv_param(param, dir_adv)) { - return -EINVAL; - } - - if (atomic_test_bit(bt_dev.flags, BT_DEV_ADVERTISING)) { - return -EALREADY; - } - - if (!bt_le_adv_random_addr_check(param)) { - return -EINVAL; - } - - (void)memset(&set_param, 0, sizeof(set_param)); - - set_param.min_interval = sys_cpu_to_le16(param->interval_min); - set_param.max_interval = sys_cpu_to_le16(param->interval_max); - set_param.channel_map = 0x07; - - if (bt_dev.adv_id != param->id) { - atomic_clear_bit(bt_dev.flags, BT_DEV_RPA_VALID); - } - -#if defined(CONFIG_BT_WHITELIST) - if ((param->options & BT_LE_ADV_OPT_FILTER_SCAN_REQ) && - (param->options & BT_LE_ADV_OPT_FILTER_CONN)) { - set_param.filter_policy = BT_LE_ADV_FP_WHITELIST_BOTH; - } else if (param->options & BT_LE_ADV_OPT_FILTER_SCAN_REQ) { - set_param.filter_policy = BT_LE_ADV_FP_WHITELIST_SCAN_REQ; - } else if (param->options & BT_LE_ADV_OPT_FILTER_CONN) { - set_param.filter_policy = BT_LE_ADV_FP_WHITELIST_CONN_IND; + if (!IS_ENABLED(CONFIG_BT_WHITELIST)) { + return BT_LE_ADV_FP_NO_WHITELIST; + } else if ((options & BT_LE_ADV_OPT_FILTER_SCAN_REQ) && + (options & BT_LE_ADV_OPT_FILTER_CONN)) { + return BT_LE_ADV_FP_WHITELIST_BOTH; + } else if (options & BT_LE_ADV_OPT_FILTER_SCAN_REQ) { + return BT_LE_ADV_FP_WHITELIST_SCAN_REQ; + } else if (options & BT_LE_ADV_OPT_FILTER_CONN) { + return BT_LE_ADV_FP_WHITELIST_CONN_IND; } else { -#else - { -#endif /* defined(CONFIG_BT_WHITELIST) */ - set_param.filter_policy = BT_LE_ADV_FP_NO_WHITELIST; + return BT_LE_ADV_FP_NO_WHITELIST; } +} + +int le_adv_set_random_addr(struct bt_le_ext_adv *adv, u32_t options, + bool dir_adv, u8_t *own_addr_type) +{ + const bt_addr_le_t *id_addr; + int err = 0; /* Set which local identity address we're advertising with */ - bt_dev.adv_id = param->id; - id_addr = &bt_dev.id_addr[param->id]; + id_addr = &bt_dev.id_addr[adv->id]; - if (param->options & BT_LE_ADV_OPT_CONNECTABLE) { + if (options & BT_LE_ADV_OPT_CONNECTABLE) { if (IS_ENABLED(CONFIG_BT_PRIVACY) && - !(param->options & BT_LE_ADV_OPT_USE_IDENTITY)) { - err = le_set_private_addr(param->id); + !(options & BT_LE_ADV_OPT_USE_IDENTITY)) { + err = le_adv_set_private_addr(adv); if (err) { return err; } if (BT_FEAT_LE_PRIVACY(bt_dev.le.features)) { - set_param.own_addr_type = - BT_HCI_OWN_ADDR_RPA_OR_RANDOM; + *own_addr_type = BT_HCI_OWN_ADDR_RPA_OR_RANDOM; } else { - set_param.own_addr_type = BT_ADDR_LE_RANDOM; + *own_addr_type = BT_ADDR_LE_RANDOM; } } else { /* @@ -6053,45 +7086,39 @@ int bt_le_adv_start_internal(const struct bt_le_adv_param *param, * could be used for advertising. */ if (id_addr->type == BT_ADDR_LE_RANDOM) { - err = set_random_address(&id_addr->a); + err = set_adv_random_address(adv, &id_addr->a); if (err) { return err; } } - set_param.own_addr_type = id_addr->type; + *own_addr_type = id_addr->type; } if (dir_adv) { - if (param->options & BT_LE_ADV_OPT_DIR_MODE_LOW_DUTY) { - set_param.type = BT_LE_ADV_DIRECT_IND_LOW_DUTY; - } else { - set_param.type = BT_LE_ADV_DIRECT_IND; - } - - bt_addr_le_copy(&set_param.direct_addr, peer); - if (IS_ENABLED(CONFIG_BT_SMP) && !IS_ENABLED(CONFIG_BT_PRIVACY) && BT_FEAT_LE_PRIVACY(bt_dev.le.features) && - (param->options & BT_LE_ADV_OPT_DIR_ADDR_RPA)) { + (options & BT_LE_ADV_OPT_DIR_ADDR_RPA)) { /* This will not use RPA for our own address * since we have set zeroed out the local IRK. */ - set_param.own_addr_type |= - BT_HCI_OWN_ADDR_RPA_MASK; + *own_addr_type |= BT_HCI_OWN_ADDR_RPA_MASK; } - } else { - set_param.type = BT_LE_ADV_IND; } } else { - if (param->options & BT_LE_ADV_OPT_USE_IDENTITY) { + if (options & BT_LE_ADV_OPT_USE_IDENTITY) { if (id_addr->type == BT_ADDR_LE_RANDOM) { - err = set_random_address(&id_addr->a); + err = set_adv_random_address(adv, &id_addr->a); } - set_param.own_addr_type = id_addr->type; - } else { + *own_addr_type = id_addr->type; + } else if (!(IS_ENABLED(CONFIG_BT_EXT_ADV) && + BT_FEAT_LE_EXT_ADV(bt_dev.le.features))) { + /* In case advertising set random address is not + * available we must handle the shared random address + * problem. + */ #if defined(CONFIG_BT_OBSERVER) bool scan_enabled = false; @@ -6104,41 +7131,307 @@ int bt_le_adv_start_internal(const struct bt_le_adv_param *param, set_le_scan_enable(false); } #endif /* defined(CONFIG_BT_OBSERVER) */ - err = le_set_private_addr(param->id); - set_param.own_addr_type = BT_ADDR_LE_RANDOM; + err = le_adv_set_private_addr(adv); + *own_addr_type = BT_ADDR_LE_RANDOM; #if defined(CONFIG_BT_OBSERVER) if (scan_enabled) { set_le_scan_enable(true); } #endif /* defined(CONFIG_BT_OBSERVER) */ + } else { + err = le_adv_set_private_addr(adv); + *own_addr_type = BT_ADDR_LE_RANDOM; + } + + if (err) { + return err; } + } + + return 0; +} + +int bt_le_adv_start_legacy(const struct bt_le_adv_param *param, + const struct bt_data *ad, size_t ad_len, + const struct bt_data *sd, size_t sd_len, + const bt_addr_le_t *peer) +{ + struct bt_hci_cp_le_set_adv_param set_param; + struct bt_conn *conn = NULL; + struct net_buf *buf; + bool dir_adv = (peer != NULL); + int err; + struct bt_le_ext_adv *adv; + + if (!atomic_test_bit(bt_dev.flags, BT_DEV_READY)) { + return -EAGAIN; + } + + if (!valid_adv_param(param, dir_adv)) { + return -EINVAL; + } + + if (atomic_test_bit(bt_dev.flags, BT_DEV_ADVERTISING)) { + return -EALREADY; + } + + if (!bt_le_adv_random_addr_check(param)) { + return -EINVAL; + } + + (void)memset(&set_param, 0, sizeof(set_param)); + + set_param.min_interval = sys_cpu_to_le16(param->interval_min); + set_param.max_interval = sys_cpu_to_le16(param->interval_max); + set_param.channel_map = 0x07; + set_param.filter_policy = get_filter_policy(param->options); + + adv = adv_new_legacy(); + if (!adv) { + BT_ERR("Legacy advertiser has no adv context"); + return -ENOMEM; + } + + if (adv->id != param->id) { + atomic_clear_bit(bt_dev.flags, BT_DEV_RPA_VALID); + } + + adv->id = param->id; + err = le_adv_set_random_addr(adv, param->options, dir_adv, + &set_param.own_addr_type); + if (err) { + return err; + } + + if (param->options & BT_LE_ADV_OPT_CONNECTABLE) { + if (dir_adv) { + if (param->options & BT_LE_ADV_OPT_DIR_MODE_LOW_DUTY) { + set_param.type = BT_HCI_ADV_DIRECT_IND_LOW_DUTY; + } else { + set_param.type = BT_HCI_ADV_DIRECT_IND; + } + + bt_addr_le_copy(&set_param.direct_addr, peer); + } else { + set_param.type = BT_HCI_ADV_IND; + } + } else { + if (sd || (param->options & BT_LE_ADV_OPT_USE_NAME)) { + set_param.type = BT_HCI_ADV_SCAN_IND; + } else { + set_param.type = BT_HCI_ADV_NONCONN_IND; + } + } + + buf = bt_hci_cmd_create(BT_HCI_OP_LE_SET_ADV_PARAM, sizeof(set_param)); + if (!buf) { + return -ENOBUFS; + } + + net_buf_add_mem(buf, &set_param, sizeof(set_param)); + + err = bt_hci_cmd_send_sync(BT_HCI_OP_LE_SET_ADV_PARAM, buf, NULL); + if (err) { + return err; + } + + if (!dir_adv) { + err = le_adv_update(adv, ad, ad_len, sd, sd_len, + param->options & BT_LE_ADV_OPT_CONNECTABLE, + param->options & BT_LE_ADV_OPT_USE_NAME); + if (err) { + return err; + } + + if (IS_ENABLED(CONFIG_BT_PERIPHERAL) && + param->options & BT_LE_ADV_OPT_CONNECTABLE) { + conn = bt_conn_add_le(param->id, BT_ADDR_LE_NONE); + if (!conn) { + return -ENOMEM; + } + + bt_conn_set_state(conn, BT_CONN_CONNECT_ADV); + } + } + + err = set_le_adv_enable(adv, true); + if (err) { + BT_ERR("Failed to start advertiser"); + if (IS_ENABLED(CONFIG_BT_PERIPHERAL) && conn) { + bt_conn_set_state(conn, BT_CONN_DISCONNECTED); + bt_conn_unref(conn); + } + return err; + } + + if (IS_ENABLED(CONFIG_BT_PERIPHERAL) && conn) { + /* If undirected connectable advertiser we have created a + * connection object that we don't yet give to the application. + * Since we don't give the application a reference to manage in + * this case, we need to release this reference here + */ + bt_conn_unref(conn); + } + + atomic_set_bit_to(bt_dev.flags, BT_DEV_KEEP_ADVERTISING, + !(param->options & BT_LE_ADV_OPT_ONE_TIME)); + + atomic_set_bit_to(bt_dev.flags, BT_DEV_ADVERTISING_NAME, + param->options & BT_LE_ADV_OPT_USE_NAME); + + atomic_set_bit_to(bt_dev.flags, BT_DEV_ADVERTISING_CONNECTABLE, + param->options & BT_LE_ADV_OPT_CONNECTABLE); + + atomic_set_bit_to(bt_dev.flags, BT_DEV_ADVERTISING_IDENTITY, + param->options & BT_LE_ADV_OPT_USE_IDENTITY); + + return 0; +} + +static int le_ext_adv_param_set(struct bt_le_ext_adv *adv, + const struct bt_le_adv_param *param, + const bt_addr_le_t *peer, + bool has_scan_data) +{ + struct bt_hci_cp_le_set_ext_adv_param *cp; + bool dir_adv = peer != NULL; + struct net_buf *buf, *rsp; + int err; + + buf = bt_hci_cmd_create(BT_HCI_OP_LE_SET_EXT_ADV_PARAM, sizeof(*cp)); + if (!buf) { + return -ENOBUFS; + } + + cp = net_buf_add(buf, sizeof(*cp)); + (void)memset(cp, 0, sizeof(*cp)); + + err = le_adv_set_random_addr(adv, param->options, dir_adv, + &cp->own_addr_type); + if (err) { + return err; + } + + sys_put_le24(param->interval_min, cp->prim_min_interval); + sys_put_le24(param->interval_max, cp->prim_max_interval); + cp->prim_channel_map = 0x07; + 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) { + if (param->options & BT_LE_ADV_OPT_NO_2M) { + cp->sec_adv_phy = BT_HCI_LE_PHY_1M; + } else { + cp->sec_adv_phy = BT_HCI_LE_PHY_2M; + } + } + + if (param->options & BT_LE_ADV_OPT_CODED) { + cp->prim_adv_phy = BT_HCI_LE_PHY_CODED; + cp->sec_adv_phy = BT_HCI_LE_PHY_CODED; + } + + if (!(param->options & BT_LE_ADV_OPT_EXT_ADV)) { + cp->props |= BT_HCI_LE_ADV_PROP_LEGACY; + } + + if (param->options & BT_LE_ADV_OPT_USE_TX_POWER) { + cp->props |= BT_HCI_LE_ADV_PROP_TX_POWER; + } + + if (param->options & BT_LE_ADV_OPT_ANONYMOUS) { + cp->props |= BT_HCI_LE_ADV_PROP_ANON; + } + + if (param->options & BT_LE_ADV_OPT_NOTIFY_SCAN_REQ) { + cp->scan_req_notify_enable = BT_HCI_LE_ADV_SCAN_REQ_ENABLE; + } + + if (param->options & BT_LE_ADV_OPT_CONNECTABLE) { + cp->props |= BT_HCI_LE_ADV_PROP_CONN; + if (dir_adv) { + cp->props |= BT_HCI_LE_ADV_PROP_DIRECT; + if (!(param->options & + BT_LE_ADV_OPT_DIR_MODE_LOW_DUTY)) { + cp->props |= BT_HCI_LE_ADV_PROP_HI_DC_CONN; + } + + bt_addr_le_copy(&cp->peer_addr, peer); + } else if (!(param->options & BT_LE_ADV_OPT_EXT_ADV)) { + /* When using non-extended adv packets then undirected + * advertising has to be scannable as well. + * We didn't require this option to be set before, so + * it is implicitly set instead in this case. + */ + cp->props |= BT_HCI_LE_ADV_PROP_SCAN; + } + } + + if (param->options & BT_LE_ADV_OPT_SCANNABLE || has_scan_data) { + cp->props |= BT_HCI_LE_ADV_PROP_SCAN; + } + + cp->sid = param->sid; + + err = bt_hci_cmd_send_sync(BT_HCI_OP_LE_SET_EXT_ADV_PARAM, buf, &rsp); + if (err) { + return err; + } + +#if defined(CONFIG_BT_EXT_ADV) + struct bt_hci_rp_le_set_ext_adv_param *rp = (void *)rsp->data; + + adv->tx_power = rp->tx_power; +#endif /* defined(CONFIG_BT_EXT_ADV) */ + + net_buf_unref(rsp); + + /* Todo: Figure out how keep advertising works with multiple adv sets */ + atomic_set_bit_to(bt_dev.flags, BT_DEV_KEEP_ADVERTISING, false); + + /* Todo: need to handle setting advertising name in correct adv/scan */ + atomic_set_bit_to(bt_dev.flags, BT_DEV_ADVERTISING_NAME, false); + + atomic_set_bit_to(bt_dev.flags, BT_DEV_ADVERTISING_CONNECTABLE, + param->options & BT_LE_ADV_OPT_CONNECTABLE); + + atomic_set_bit_to(bt_dev.flags, BT_DEV_ADVERTISING_IDENTITY, + param->options & BT_LE_ADV_OPT_USE_IDENTITY); + + return 0; +} + +int bt_le_adv_start_ext(struct bt_le_ext_adv *adv, + const struct bt_le_adv_param *param, + const struct bt_data *ad, size_t ad_len, + const struct bt_data *sd, size_t sd_len, + const bt_addr_le_t *peer) +{ + bool dir_adv = (peer != NULL); + struct bt_conn *conn = NULL; + int err = 0; - if (err) { - return err; - } + if (!atomic_test_bit(bt_dev.flags, BT_DEV_READY)) { + return -EAGAIN; + } - if (sd || (param->options & BT_LE_ADV_OPT_USE_NAME)) { - set_param.type = BT_LE_ADV_SCAN_IND; - } else { - set_param.type = BT_LE_ADV_NONCONN_IND; - } + if (!valid_adv_param(param, dir_adv)) { + return -EINVAL; } - buf = bt_hci_cmd_create(BT_HCI_OP_LE_SET_ADV_PARAM, sizeof(set_param)); - if (!buf) { - return -ENOBUFS; + if (atomic_test_bit(bt_dev.flags, BT_DEV_ADVERTISING)) { + return -EALREADY; } - net_buf_add_mem(buf, &set_param, sizeof(set_param)); + adv->id = param->id; - err = bt_hci_cmd_send_sync(BT_HCI_OP_LE_SET_ADV_PARAM, buf, NULL); - if (err) { - return err; - } + le_ext_adv_param_set(adv, param, peer, + sd || (param->options & BT_LE_ADV_OPT_USE_NAME)); if (!dir_adv) { - err = le_adv_update(ad, ad_len, sd, sd_len, + err = le_adv_update(adv, ad, ad_len, sd, sd_len, param->options & BT_LE_ADV_OPT_CONNECTABLE, param->options & BT_LE_ADV_OPT_USE_NAME); if (err) { @@ -6156,13 +7449,14 @@ int bt_le_adv_start_internal(const struct bt_le_adv_param *param, } } - err = set_advertise_enable(true); + err = set_le_adv_enable_ext(adv, true, NULL); if (err) { BT_ERR("Failed to start advertiser"); if (IS_ENABLED(CONFIG_BT_PERIPHERAL) && conn) { bt_conn_set_state(conn, BT_CONN_DISCONNECTED); bt_conn_unref(conn); } + return err; } @@ -6181,13 +7475,33 @@ int bt_le_adv_start_internal(const struct bt_le_adv_param *param, atomic_set_bit_to(bt_dev.flags, BT_DEV_ADVERTISING_NAME, param->options & BT_LE_ADV_OPT_USE_NAME); - atomic_set_bit_to(bt_dev.flags, BT_DEV_ADVERTISING_CONNECTABLE, - param->options & BT_LE_ADV_OPT_CONNECTABLE); + return 0; +} - atomic_set_bit_to(bt_dev.flags, BT_DEV_ADVERTISING_IDENTITY, - param->options & BT_LE_ADV_OPT_USE_IDENTITY); +int bt_le_adv_start_internal(const struct bt_le_adv_param *param, + const struct bt_data *ad, size_t ad_len, + const struct bt_data *sd, size_t sd_len, + const bt_addr_le_t *peer) +{ + if (IS_ENABLED(CONFIG_BT_EXT_ADV) && + BT_FEAT_LE_EXT_ADV(bt_dev.le.features)) { + struct bt_le_ext_adv *adv = adv_new_legacy(); + int err; - return 0; + if (!adv) { + return -ENOMEM; + } + + err = bt_le_adv_start_ext(adv, param, ad, ad_len, sd, sd_len, + peer); + if (err) { + adv_delete_legacy(); + } + + return err; + } + + return bt_le_adv_start_legacy(param, ad, ad_len, sd, sd_len, peer); } int bt_le_adv_start(const struct bt_le_adv_param *param, @@ -6211,20 +7525,22 @@ int bt_le_adv_stop(void) atomic_clear_bit(bt_dev.flags, BT_DEV_KEEP_ADVERTISING); if (!atomic_test_bit(bt_dev.flags, BT_DEV_ADVERTISING)) { + adv_delete_legacy(); return 0; } if (IS_ENABLED(CONFIG_BT_PERIPHERAL)) { + struct bt_le_ext_adv *adv = bt_adv_lookup_legacy(); struct bt_conn *conn; - conn = bt_conn_lookup_state_le(bt_dev.adv_id, BT_ADDR_LE_NONE, + conn = bt_conn_lookup_state_le(adv->id, BT_ADDR_LE_NONE, BT_CONN_CONNECT_ADV); if (conn) { bt_conn_set_state(conn, BT_CONN_DISCONNECTED); bt_conn_unref(conn); } - conn = bt_conn_lookup_state_le(bt_dev.adv_id, NULL, + conn = bt_conn_lookup_state_le(adv->id, NULL, BT_CONN_CONNECT_DIR_ADV); if (conn) { bt_conn_set_state(conn, BT_CONN_DISCONNECTED); @@ -6232,18 +7548,37 @@ int bt_le_adv_stop(void) } } - err = set_advertise_enable(false); - if (err) { - return err; + if (IS_ENABLED(CONFIG_BT_EXT_ADV) && + BT_FEAT_LE_EXT_ADV(bt_dev.le.features)) { + struct bt_le_ext_adv *adv = bt_adv_lookup_legacy(); + + if (!adv) { + BT_ERR("Advertising but no adv context"); + return 0; + } + + err = set_le_adv_enable_ext(adv, false, NULL); + if (err) { + return err; + } + } else { + err = set_le_adv_enable_legacy(false); + if (err) { + return err; + } } + adv_delete_legacy(); + #if defined(CONFIG_BT_OBSERVER) - if (!IS_ENABLED(CONFIG_BT_PRIVACY) && + if (!(IS_ENABLED(CONFIG_BT_EXT_ADV) && + BT_FEAT_LE_EXT_ADV(bt_dev.le.features)) && + !IS_ENABLED(CONFIG_BT_PRIVACY) && !IS_ENABLED(CONFIG_BT_SCAN_WITH_IDENTITY)) { /* If scan is ongoing set back NRPA */ if (atomic_test_bit(bt_dev.flags, BT_DEV_SCANNING)) { set_le_scan_enable(BT_HCI_LE_SCAN_DISABLE); - le_set_private_addr(bt_dev.adv_id); + le_set_private_addr(BT_ID_DEFAULT); set_le_scan_enable(BT_HCI_LE_SCAN_ENABLE); } } @@ -6255,13 +7590,19 @@ int bt_le_adv_stop(void) #if defined(CONFIG_BT_PERIPHERAL) void bt_le_adv_resume(void) { + struct bt_le_ext_adv *adv = bt_adv_lookup_legacy(); struct bt_conn *adv_conn; int err; + if (!adv) { + BT_WARN("Not legacy advertiser"); + return; + } + BT_ASSERT(atomic_test_bit(bt_dev.flags, BT_DEV_ADVERTISING_CONNECTABLE)); - adv_conn = bt_conn_add_le(bt_dev.adv_id, BT_ADDR_LE_NONE); + adv_conn = bt_conn_add_le(adv->id, BT_ADDR_LE_NONE); if (!adv_conn) { return; } @@ -6270,10 +7611,10 @@ void bt_le_adv_resume(void) if (IS_ENABLED(CONFIG_BT_PRIVACY) && !atomic_test_bit(bt_dev.flags, BT_DEV_ADVERTISING_IDENTITY)) { - le_set_private_addr(bt_dev.adv_id); + le_adv_set_private_addr(adv); } - err = set_advertise_enable(true); + err = set_le_adv_enable(adv, true); if (err) { bt_conn_set_state(adv_conn, BT_CONN_DISCONNECTED); } @@ -6283,8 +7624,205 @@ void bt_le_adv_resume(void) */ bt_conn_unref(adv_conn); } + #endif /* defined(CONFIG_BT_PERIPHERAL) */ +#if defined(CONFIG_BT_EXT_ADV) +static bool valid_adv_ext_param(const struct bt_le_adv_param *param) +{ + return valid_adv_param(param, false); +} + +int bt_le_ext_adv_get_info(const struct bt_le_ext_adv *adv, + struct bt_le_ext_adv_info *info) +{ + info->id = adv->id; + info->tx_power = adv->tx_power; + + return 0; +} + +int bt_le_ext_adv_create(const struct bt_le_adv_param *param, + const struct bt_le_ext_adv_cb *cb, + struct bt_le_ext_adv **out_adv) +{ + struct bt_le_ext_adv *adv; + int err; + + if (!atomic_test_bit(bt_dev.flags, BT_DEV_READY)) { + return -EAGAIN; + } + + if (!valid_adv_ext_param(param)) { + return -EINVAL; + } + + adv = adv_new(); + if (!adv) { + return -ENOMEM; + } + + adv->id = param->id; + adv->cb = cb; + + err = le_ext_adv_param_set(adv, param, NULL, false); + if (err) { + adv_delete(adv); + return err; + } + + *out_adv = adv; + return 0; +} + +int bt_le_ext_adv_update_param(struct bt_le_ext_adv *adv, + const struct bt_le_adv_param *param) +{ + if (!valid_adv_ext_param(param)) { + return -EINVAL; + } + + if (atomic_test_bit(bt_dev.flags, BT_DEV_ADVERTISING)) { + return -EINVAL; + } + + if (param->id != adv->id) { + atomic_clear_bit(adv->flags, BT_ADV_RPA_VALID); + } + + return le_ext_adv_param_set(adv, param, NULL, false); +} + +int bt_le_ext_adv_start(struct bt_le_ext_adv *adv, + struct bt_le_ext_adv_start_param *param) +{ + struct bt_conn *conn = NULL; + int err; + + if (IS_ENABLED(CONFIG_BT_PERIPHERAL) && + atomic_test_bit(bt_dev.flags, BT_DEV_ADVERTISING_CONNECTABLE)) { + conn = bt_conn_add_le(adv->id, BT_ADDR_LE_NONE); + if (!conn) { + return -ENOMEM; + } + + bt_conn_set_state(conn, BT_CONN_CONNECT_ADV); + } + + atomic_set_bit_to(adv->flags, BT_ADV_LIMITED, param && + (param->timeout > 0 || param->num_events > 0)); + + le_adv_set_private_addr(adv); + + err = set_le_adv_enable_ext(adv, true, param); + if (err) { + BT_ERR("Failed to start advertiser"); + if (IS_ENABLED(CONFIG_BT_PERIPHERAL) && conn) { + bt_conn_set_state(conn, BT_CONN_DISCONNECTED); + bt_conn_unref(conn); + } + + return err; + } + + if (IS_ENABLED(CONFIG_BT_PERIPHERAL) && conn) { + /* If undirected connectable advertiser we have created a + * connection object that we don't yet give to the application. + * Since we don't give the application a reference to manage in + * this case, we need to release this reference here + */ + bt_conn_unref(conn); + } + + return 0; +} + +int bt_le_ext_adv_stop(struct bt_le_ext_adv *adv) +{ + atomic_clear_bit(bt_dev.flags, BT_DEV_KEEP_ADVERTISING); + + if (!atomic_test_bit(bt_dev.flags, BT_DEV_ADVERTISING)) { + return 0; + } + + if (atomic_test_and_clear_bit(adv->flags, BT_ADV_LIMITED)) { + atomic_clear_bit(adv->flags, BT_ADV_RPA_VALID); + +#if defined(CONFIG_BT_SMP) + pending_id_keys_update(); +#endif + } + + if (IS_ENABLED(CONFIG_BT_PERIPHERAL)) { + struct bt_conn *conn; + + conn = bt_conn_lookup_state_le(adv->id, BT_ADDR_LE_NONE, + BT_CONN_CONNECT_ADV); + if (conn) { + bt_conn_set_state(conn, BT_CONN_DISCONNECTED); + bt_conn_unref(conn); + } + + conn = bt_conn_lookup_state_le(adv->id, NULL, + BT_CONN_CONNECT_DIR_ADV); + if (conn) { + bt_conn_set_state(conn, BT_CONN_DISCONNECTED); + bt_conn_unref(conn); + } + } + + return set_le_adv_enable_ext(adv, false, NULL); +} + +int bt_le_ext_adv_set_data(struct bt_le_ext_adv *adv, + const struct bt_data *ad, size_t ad_len, + const struct bt_data *sd, size_t sd_len) +{ + bool connectable, use_name; + + connectable = atomic_test_bit(bt_dev.flags, + BT_DEV_ADVERTISING_CONNECTABLE); + use_name = atomic_test_bit(bt_dev.flags, BT_DEV_ADVERTISING_NAME); + + return le_adv_update(adv, ad, ad_len, sd, sd_len, connectable, + use_name); +} + +int bt_le_ext_adv_delete(struct bt_le_ext_adv *adv) +{ + struct bt_hci_cp_le_remove_adv_set *cp; + struct net_buf *buf; + int err; + + if (!BT_FEAT_LE_EXT_ADV(bt_dev.le.features)) { + return -ENOTSUP; + } + + /* Advertising set should be stopped first */ + if (atomic_test_bit(bt_dev.flags, BT_DEV_ADVERTISING)) { + return -EINVAL; + } + + buf = bt_hci_cmd_create(BT_HCI_OP_LE_REMOVE_ADV_SET, sizeof(*cp)); + if (!buf) { + BT_WARN("No HCI buffers"); + return -ENOBUFS; + } + + cp = net_buf_add(buf, sizeof(*cp)); + cp->handle = adv->handle; + + err = bt_hci_cmd_send_sync(BT_HCI_OP_LE_REMOVE_ADV_SET, buf, NULL); + if (err) { + return err; + } + + adv_delete(adv); + + return 0; +} +#endif /* defined(CONFIG_BT_EXT_ADV) */ + #if defined(CONFIG_BT_OBSERVER) static bool valid_le_scan_param(const struct bt_le_scan_param *param) { @@ -6293,8 +7831,10 @@ static bool valid_le_scan_param(const struct bt_le_scan_param *param) return false; } - if (param->filter_dup & - ~(BT_LE_SCAN_FILTER_DUPLICATE | BT_LE_SCAN_FILTER_WHITELIST)) { + if (param->options & ~(BT_LE_SCAN_OPT_FILTER_DUPLICATE | + BT_LE_SCAN_OPT_FILTER_WHITELIST | + BT_LE_SCAN_OPT_CODED | + BT_LE_SCAN_OPT_NO_1M)) { return false; } @@ -6329,6 +7869,7 @@ int bt_le_scan_start(const struct bt_le_scan_param *param, bt_le_scan_cb_t cb) if (param->type && !bt_le_scan_random_addr_check()) { return -EINVAL; } + /* Return if active scan is already enabled */ if (atomic_test_and_set_bit(bt_dev.flags, BT_DEV_EXPLICIT_SCAN)) { return -EALREADY; @@ -6343,14 +7884,53 @@ int bt_le_scan_start(const struct bt_le_scan_param *param, bt_le_scan_cb_t cb) } atomic_set_bit_to(bt_dev.flags, BT_DEV_SCAN_FILTER_DUP, - param->filter_dup & BT_LE_SCAN_FILTER_DUPLICATE); + param->options & BT_LE_SCAN_OPT_FILTER_DUPLICATE); #if defined(CONFIG_BT_WHITELIST) atomic_set_bit_to(bt_dev.flags, BT_DEV_SCAN_WL, - param->filter_dup & BT_LE_SCAN_FILTER_WHITELIST); + param->options & BT_LE_SCAN_OPT_FILTER_WHITELIST); #endif /* defined(CONFIG_BT_WHITELIST) */ - err = start_le_scan(param->type, param->interval, param->window); + if (IS_ENABLED(CONFIG_BT_EXT_ADV) && + BT_FEAT_LE_EXT_ADV(bt_dev.le.features)) { + struct bt_hci_ext_scan_phy param_1m; + struct bt_hci_ext_scan_phy param_coded; + + struct bt_hci_ext_scan_phy *phy_1m = NULL; + struct bt_hci_ext_scan_phy *phy_coded = NULL; + + if (!(param->options & BT_LE_SCAN_OPT_NO_1M)) { + param_1m.type = param->type; + param_1m.interval = sys_cpu_to_le16(param->interval); + param_1m.window = sys_cpu_to_le16(param->window); + + phy_1m = ¶m_1m; + } + + if (param->options & BT_LE_SCAN_OPT_CODED) { + u16_t interval = param->interval_coded ? + param->interval_coded : + param->interval; + u16_t window = param->window_coded ? + param->window_coded : + param->window; + + param_coded.type = param->type; + param_coded.interval = sys_cpu_to_le16(interval); + param_coded.window = sys_cpu_to_le16(window); + phy_coded = ¶m_coded; + } + + err = start_le_scan_ext(phy_1m, phy_coded, param->timeout); + } else { + if (param->timeout) { + return -ENOTSUP; + } + + err = start_le_scan_legacy(param->type, param->interval, + param->window); + } + if (err) { atomic_clear_bit(bt_dev.flags, BT_DEV_EXPLICIT_SCAN); return err; @@ -6370,6 +7950,15 @@ int bt_le_scan_stop(void) scan_dev_found_cb = NULL; + if (IS_ENABLED(CONFIG_BT_EXT_ADV) && + atomic_test_and_clear_bit(bt_dev.flags, BT_DEV_SCAN_LIMITED)) { + atomic_clear_bit(bt_dev.flags, BT_DEV_RPA_VALID); + +#if defined(CONFIG_BT_SMP) + pending_id_keys_update(); +#endif + } + return bt_le_scan_update(false); } @@ -6849,6 +8438,7 @@ int bt_br_oob_get_local(struct bt_br_oob *oob) int bt_le_oob_get_local(u8_t id, struct bt_le_oob *oob) { + struct bt_le_ext_adv *adv; int err; if (!atomic_test_bit(bt_dev.flags, BT_DEV_READY)) { @@ -6859,10 +8449,12 @@ int bt_le_oob_get_local(u8_t id, struct bt_le_oob *oob) return -EINVAL; } + adv = bt_adv_lookup_legacy(); + if (IS_ENABLED(CONFIG_BT_PRIVACY) && - !(atomic_test_bit(bt_dev.flags, BT_DEV_ADVERTISING) && + !(adv && adv->id == id && + atomic_test_bit(bt_dev.flags, BT_DEV_ADVERTISING) && atomic_test_bit(bt_dev.flags, BT_DEV_ADVERTISING_IDENTITY) && - bt_dev.adv_id == id && bt_dev.id_addr[id].type == BT_ADDR_LE_RANDOM)) { if (IS_ENABLED(CONFIG_BT_CENTRAL) && atomic_test_bit(bt_dev.flags, BT_DEV_INITIATING)) { @@ -6898,8 +8490,7 @@ int bt_le_oob_get_local(u8_t id, struct bt_le_oob *oob) return -EINVAL; } - /* Invalidate RPA so a new one is generated */ - atomic_clear_bit(bt_dev.flags, BT_DEV_RPA_VALID); + le_rpa_invalidate(); le_update_private_addr(); bt_addr_le_copy(&oob->addr, &bt_dev.random_addr); @@ -6907,6 +8498,61 @@ int bt_le_oob_get_local(u8_t id, struct bt_le_oob *oob) bt_addr_le_copy(&oob->addr, &bt_dev.id_addr[id]); } + if (IS_ENABLED(CONFIG_BT_SMP)) { + err = bt_smp_le_oob_generate_sc_data(&oob->le_sc_data); + if (err) { + return err; + } + } + + return 0; +} + +#if defined(CONFIG_BT_EXT_ADV) +int bt_le_ext_adv_oob_get_local(struct bt_le_ext_adv *adv, + struct bt_le_oob *oob) +{ + int err; + + if (!atomic_test_bit(bt_dev.flags, BT_DEV_READY)) { + return -EAGAIN; + } + + if (IS_ENABLED(CONFIG_BT_PRIVACY) && + !atomic_test_bit(bt_dev.flags, BT_DEV_ADVERTISING_IDENTITY)) { + /* Don't refresh RPA addresses if there is less than + * half a second since it was refreshed last time. + * This allows back to back calls to this function to not + * invalidate the previously set RPAs. + */ + if (!atomic_test_bit(adv->flags, BT_ADV_LIMITED) && + k_delayed_work_remaining_get(&bt_dev.rpa_update) < + (RPA_TIMEOUT - K_MSEC(500))) { + if (IS_ENABLED(CONFIG_BT_CENTRAL) && + atomic_test_bit(bt_dev.flags, BT_DEV_INITIATING)) { + struct bt_conn *conn; + + conn = bt_conn_lookup_state_le( + BT_ID_DEFAULT, NULL, + BT_CONN_CONNECT_SCAN); + + if (conn) { + /* Cannot set new RPA while creating + * connections. + */ + bt_conn_unref(conn); + return -EINVAL; + } + } + + le_rpa_invalidate(); + le_update_private_addr(); + } + + bt_addr_le_copy(&oob->addr, &adv->random_addr); + } else { + bt_addr_le_copy(&oob->addr, &bt_dev.id_addr[adv->id]); + } if (IS_ENABLED(CONFIG_BT_SMP) && !IS_ENABLED(CONFIG_BT_SMP_OOB_LEGACY_PAIR_ONLY)) { @@ -6918,6 +8564,7 @@ int bt_le_oob_get_local(u8_t id, struct bt_le_oob *oob) return 0; } +#endif /* defined(CONFIG_BT_EXT_ADV) */ #if defined(CONFIG_BT_SMP) #if !defined(CONFIG_BT_SMP_SC_PAIR_ONLY) diff --git a/subsys/bluetooth/host/hci_core.h b/subsys/bluetooth/host/hci_core.h index 5a27b9f17f65..417b528e6c74 100644 --- a/subsys/bluetooth/host/hci_core.h +++ b/subsys/bluetooth/host/hci_core.h @@ -43,9 +43,11 @@ enum { BT_DEV_ACTIVE_SCAN, BT_DEV_SCAN_FILTER_DUP, BT_DEV_SCAN_WL, + BT_DEV_SCAN_LIMITED, BT_DEV_INITIATING, BT_DEV_RPA_VALID, + BT_DEV_RPA_TIMEOUT_SET, BT_DEV_ID_PENDING, BT_DEV_STORE_ID, @@ -64,6 +66,36 @@ enum { #define BT_DEV_PERSISTENT_FLAGS (BIT(BT_DEV_ENABLE) | \ BIT(BT_DEV_PRESET_ID)) +enum { + BT_ADV_CREATED, + + BT_ADV_RPA_VALID, + + BT_ADV_LIMITED, + + BT_ADV_NUM_FLAGS, +}; + +struct bt_le_ext_adv { + /* ID Address used for advertising */ + u8_t id; + + /* Advertising handle */ + u16_t handle; + + /* Current local Random Address */ + bt_addr_le_t random_addr; + + ATOMIC_DEFINE(flags, BT_ADV_NUM_FLAGS); + +#if defined(CONFIG_BT_EXT_ADV) + const struct bt_le_ext_adv_cb *cb; + + /* TX Power in use by the controller */ + s8_t tx_power; +#endif /* defined(CONFIG_BT_EXT_ADV) */ +}; + struct bt_dev_le { /* LE features */ u8_t features[8]; @@ -109,11 +141,17 @@ struct bt_dev { bt_addr_le_t id_addr[CONFIG_BT_ID_MAX]; u8_t id_count; - /* ID Address used for advertising */ - u8_t adv_id; + struct bt_conn_le_create_param create_param; +#if !defined(CONFIG_BT_EXT_ADV) + /* Legacy advertiser */ + struct bt_le_ext_adv adv; +#else + /* Pointer to reserved advertising set */ + struct bt_le_ext_adv *adv; +#endif /* Current local Random Address */ - bt_addr_le_t random_addr; + bt_addr_le_t random_addr; /* Controller version & manufacturer information */ u8_t hci_version; @@ -210,5 +248,6 @@ int bt_le_adv_start_internal(const struct bt_le_adv_param *param, const struct bt_data *ad, size_t ad_len, const struct bt_data *sd, size_t sd_len, const bt_addr_le_t *peer); + void bt_le_adv_resume(void); bool bt_le_scan_random_addr_check(void); diff --git a/subsys/bluetooth/mesh/adv.c b/subsys/bluetooth/mesh/adv.c index 03eb64a3316c..319cb0155492 100644 --- a/subsys/bluetooth/mesh/adv.c +++ b/subsys/bluetooth/mesh/adv.c @@ -256,7 +256,7 @@ void bt_mesh_adv_send(struct net_buf *buf, const struct bt_mesh_send_cb *cb, static void bt_mesh_scan_cb(const bt_addr_le_t *addr, s8_t rssi, u8_t adv_type, struct net_buf_simple *buf) { - if (adv_type != BT_LE_ADV_NONCONN_IND) { + if (adv_type != BT_GAP_ADV_TYPE_ADV_NONCONN_IND) { return; } @@ -316,7 +316,7 @@ int bt_mesh_scan_enable(void) { struct bt_le_scan_param scan_param = { .type = BT_HCI_LE_SCAN_PASSIVE, - .filter_dup = BT_HCI_LE_SCAN_FILTER_DUP_DISABLE, + .filter_dup = BT_LE_SCAN_OPT_NONE, .interval = MESH_SCAN_INTERVAL, .window = MESH_SCAN_WINDOW }; int err; diff --git a/subsys/bluetooth/shell/bt.c b/subsys/bluetooth/shell/bt.c index da50089c2fe5..0e94bd0480ec 100644 --- a/subsys/bluetooth/shell/bt.c +++ b/subsys/bluetooth/shell/bt.c @@ -56,6 +56,11 @@ static struct bt_le_oob oob_remote; #define KEY_STR_LEN 33 +#if defined(CONFIG_BT_EXT_ADV) +static u8_t selected_adv; +struct bt_le_ext_adv *adv_sets[CONFIG_BT_EXT_ADV_MAX_ADV_SET]; +#endif + #if defined(CONFIG_BT_OBSERVER) static bool data_cb(struct bt_data *data, void *user_data) { @@ -71,8 +76,19 @@ static bool data_cb(struct bt_data *data, void *user_data) } } -static void device_found(const bt_addr_le_t *addr, s8_t rssi, u8_t evtype, - struct net_buf_simple *buf) +static const char *phy2str(u8_t phy) +{ + switch (phy) { + case 0: return "No packets"; + case BT_GAP_LE_PHY_1M: return "LE 1M"; + case BT_GAP_LE_PHY_2M: return "LE 2M"; + case BT_GAP_LE_PHY_CODED: return "LE Coded"; + default: return "Unknown"; + } +} + +static void scan_recv(const struct bt_le_scan_recv_info *info, + struct net_buf_simple *buf) { char le_addr[BT_ADDR_LE_STR_LEN]; char name[NAME_LEN]; @@ -81,12 +97,55 @@ static void device_found(const bt_addr_le_t *addr, s8_t rssi, u8_t evtype, bt_data_parse(buf, data_cb, name); - bt_addr_le_to_str(addr, le_addr, sizeof(le_addr)); - shell_print(ctx_shell, "[DEVICE]: %s, AD evt type %u, RSSI %i %s", - le_addr, evtype, rssi, name); + bt_addr_le_to_str(info->addr, le_addr, sizeof(le_addr)); + shell_print(ctx_shell, "[DEVICE]: %s, AD evt type %u, RSSI %i %s " + "C:%u S:%u D:%d SR:%u E:%u Prim: %s, Secn: %s", + le_addr, info->adv_type, info->rssi, name, + (info->adv_props & BT_GAP_ADV_PROP_CONNECTABLE) != 0, + (info->adv_props & BT_GAP_ADV_PROP_SCANNABLE) != 0, + (info->adv_props & BT_GAP_ADV_PROP_DIRECTED) != 0, + (info->adv_props & BT_GAP_ADV_PROP_SCAN_RESPONSE) != 0, + (info->adv_props & BT_GAP_ADV_PROP_EXT_ADV) != 0, + phy2str(info->primary_phy), phy2str(info->secondary_phy)); +} + +static void scan_timeout(void) +{ + shell_print(ctx_shell, "Scan timeout"); } #endif /* CONFIG_BT_OBSERVER */ +#if defined(CONFIG_BT_BROADCASTER) && defined(CONFIG_BT_EXT_ADV) +static void adv_sent(struct bt_le_ext_adv *adv, + struct bt_le_ext_adv_sent_info *info) +{ + shell_print(ctx_shell, "Advertiser[%d] %p sent %d", + bt_le_ext_adv_get_index(adv), adv, info->num_sent); +} + +static void adv_connected(struct bt_le_ext_adv *adv, + struct bt_le_ext_adv_connected_info *info) +{ + char str[BT_ADDR_LE_STR_LEN]; + + bt_addr_le_to_str(bt_conn_get_dst(info->conn), str, sizeof(str)); + + shell_print(ctx_shell, "Advertiser[%d] %p connected by %s", + bt_le_ext_adv_get_index(adv), adv, str); +} + +static void adv_scanned(struct bt_le_ext_adv *adv, + struct bt_le_ext_adv_scanned_info *info) +{ + char str[BT_ADDR_LE_STR_LEN]; + + bt_addr_le_to_str(info->addr, str, sizeof(str)); + + shell_print(ctx_shell, "Advertiser[%d] %p scanned by %s", + bt_le_ext_adv_get_index(adv), adv, str); +} +#endif /* defined(CONFIG_BT_BROADCASTER) && defined(CONFIG_BT_EXT_ADV) */ + #if !defined(CONFIG_BT_CONN) #if 0 /* FIXME: Add support for changing prompt */ static const char *current_prompt(void) @@ -142,6 +201,22 @@ void conn_addr_str(struct bt_conn *conn, char *addr, size_t len) } } +static void print_le_oob(const struct shell *shell, struct bt_le_oob *oob) +{ + char addr[BT_ADDR_LE_STR_LEN]; + char c[KEY_STR_LEN]; + char r[KEY_STR_LEN]; + + bt_addr_le_to_str(&oob->addr, addr, sizeof(addr)); + + bin2hex(oob->le_sc_data.c, sizeof(oob->le_sc_data.c), c, sizeof(c)); + bin2hex(oob->le_sc_data.r, sizeof(oob->le_sc_data.r), r, sizeof(r)); + + shell_print(shell, "OOB data:"); + shell_print(shell, "%-29s %-32s %-32s", "addr", "random", "confirm"); + shell_print(shell, "%29s %32s %32s", addr, r, c); +} + static void connected(struct bt_conn *conn, u8_t err) { char addr[BT_ADDR_LE_STR_LEN]; @@ -149,7 +224,7 @@ static void connected(struct bt_conn *conn, u8_t err) conn_addr_str(conn, addr, sizeof(addr)); if (err) { - shell_error(ctx_shell, "Failed to connect to %s (%u)", addr, + shell_error(ctx_shell, "Failed to connect to %s (0x%02x)", addr, err); goto done; } @@ -290,6 +365,21 @@ static struct bt_conn_cb conn_callbacks = { }; #endif /* CONFIG_BT_CONN */ +#if defined(CONFIG_BT_OBSERVER) +static struct bt_le_scan_cb scan_callbacks = { + .recv = scan_recv, + .timeout = scan_timeout, +}; +#endif /* defined(CONFIG_BT_OBSERVER) */ + +#if defined(CONFIG_BT_BROADCASTER) && defined(CONFIG_BT_EXT_ADV) +static struct bt_le_ext_adv_cb adv_callbacks = { + .sent = adv_sent, + .connected = adv_connected, + .scanned = adv_scanned, +}; +#endif /* defined(CONFIG_BT_BROADCASTER) && defined(CONFIG_BT_EXT_ADV) */ + static void bt_ready(int err) { if (err) { @@ -307,6 +397,10 @@ static void bt_ready(int err) bt_set_oob_data_flag(true); } +#if defined(CONFIG_BT_OBSERVER) + bt_le_scan_cb_register(&scan_callbacks); +#endif + #if defined(CONFIG_BT_CONN) default_conn = NULL; @@ -507,18 +601,20 @@ static int cmd_id_select(const struct shell *shell, size_t argc, char *argv[]) } #if defined(CONFIG_BT_OBSERVER) -static int cmd_active_scan_on(const struct shell *shell, u8_t filter) +static int cmd_active_scan_on(const struct shell *shell, u32_t options, + u16_t timeout) { int err; struct bt_le_scan_param param = { - .type = BT_HCI_LE_SCAN_ACTIVE, - .filter_dup = BT_HCI_LE_SCAN_FILTER_DUP_ENABLE, + .type = BT_LE_SCAN_TYPE_ACTIVE, + .options = BT_LE_SCAN_OPT_FILTER_DUPLICATE, .interval = BT_GAP_SCAN_FAST_INTERVAL, - .window = BT_GAP_SCAN_FAST_WINDOW }; + .window = BT_GAP_SCAN_FAST_WINDOW, + .timeout = timeout, }; - param.filter_dup = filter; + param.options |= options; - err = bt_le_scan_start(¶m, device_found); + err = bt_le_scan_start(¶m, NULL); if (err) { shell_error(shell, "Bluetooth set active scan failed " "(err %d)", err); @@ -530,18 +626,20 @@ static int cmd_active_scan_on(const struct shell *shell, u8_t filter) return 0; } -static int cmd_passive_scan_on(const struct shell *shell, u8_t filter) +static int cmd_passive_scan_on(const struct shell *shell, u32_t options, + u16_t timeout) { struct bt_le_scan_param param = { - .type = BT_HCI_LE_SCAN_PASSIVE, - .filter_dup = BT_HCI_LE_SCAN_FILTER_DUP_DISABLE, + .type = BT_LE_SCAN_TYPE_PASSIVE, + .options = BT_LE_SCAN_OPT_NONE, .interval = 0x10, - .window = 0x10 }; + .window = 0x10, + .timeout = timeout, }; int err; - param.filter_dup = filter; + param.options |= options; - err = bt_le_scan_start(¶m, device_found); + err = bt_le_scan_start(¶m, NULL); if (err) { shell_error(shell, "Bluetooth set passive scan failed " "(err %d)", err); @@ -571,18 +669,30 @@ static int cmd_scan_off(const struct shell *shell) static int cmd_scan(const struct shell *shell, size_t argc, char *argv[]) { const char *action; - u8_t filter = 0; + u32_t options = 0; + u16_t timeout = 0; /* Parse duplicate filtering data */ for (size_t argn = 2; argn < argc; argn++) { const char *arg = argv[argn]; if (!strcmp(arg, "dups")) { - filter |= BT_LE_SCAN_FILTER_DUPLICATE; + options |= BT_LE_SCAN_OPT_FILTER_DUPLICATE; } else if (!strcmp(arg, "nodups")) { - filter &= ~BT_LE_SCAN_FILTER_DUPLICATE; + options &= ~BT_LE_SCAN_OPT_FILTER_DUPLICATE; } else if (!strcmp(arg, "wl")) { - filter |= BT_LE_SCAN_FILTER_WHITELIST; + options |= BT_LE_SCAN_OPT_FILTER_WHITELIST; + } else if (!strcmp(arg, "coded")) { + options |= BT_LE_SCAN_OPT_CODED; + } else if (!strcmp(arg, "no-1m")) { + options |= BT_LE_SCAN_OPT_NO_1M; + } else if (!strcmp(arg, "timeout")) { + if (++argn == argc) { + shell_help(shell); + return SHELL_CMD_HELP_PRINTED; + } + + timeout = strtoul(argv[argn], NULL, 16); } else { shell_help(shell); return SHELL_CMD_HELP_PRINTED; @@ -591,11 +701,11 @@ static int cmd_scan(const struct shell *shell, size_t argc, char *argv[]) action = argv[1]; if (!strcmp(action, "on")) { - return cmd_active_scan_on(shell, filter); + return cmd_active_scan_on(shell, options, timeout); } else if (!strcmp(action, "off")) { return cmd_scan_off(shell); } else if (!strcmp(action, "passive")) { - return cmd_passive_scan_on(shell, filter); + return cmd_passive_scan_on(shell, options, timeout); } else { shell_help(shell); return SHELL_CMD_HELP_PRINTED; @@ -708,9 +818,10 @@ static int cmd_directed_adv(const struct shell *shell, } } - conn = bt_conn_create_slave_le(&addr, param); - if (!conn) { - shell_error(shell, "Failed to start directed advertising"); + err = bt_conn_le_create_slave(&addr, param, &conn); + if (err) { + shell_error(shell, "Failed to start directed advertising (%d)", + err); return -ENOEXEC; } else { shell_print(shell, "Started directed advertising"); @@ -722,6 +833,303 @@ static int cmd_directed_adv(const struct shell *shell, return 0; } #endif /* CONFIG_BT_PERIPHERAL */ + +#if defined(CONFIG_BT_EXT_ADV) +static bool adv_param_parse(size_t argc, char *argv[], + struct bt_le_adv_param *param) +{ + param->options = 0; + + if (!strcmp(argv[1], "conn-scan")) { + param->options |= BT_LE_ADV_OPT_CONNECTABLE; + param->options |= BT_LE_ADV_OPT_SCANNABLE; + } else if (!strcmp(argv[1], "conn-nscan")) { + param->options |= BT_LE_ADV_OPT_CONNECTABLE; + } else if (!strcmp(argv[1], "nconn-scan")) { + param->options |= BT_LE_ADV_OPT_SCANNABLE; + } else if (!strcmp(argv[1], "nconn-nscan")) { + /* Acceptable option, nothing to do */ + } else { + return false; + } + + for (size_t argn = 2; argn < argc; argn++) { + const char *arg = argv[argn]; + + if (!strcmp(arg, "ext-adv")) { + param->options |= BT_LE_ADV_OPT_EXT_ADV; + } else if (!strcmp(arg, "coded")) { + param->options |= BT_LE_ADV_OPT_CODED; + } else if (!strcmp(arg, "no-2m")) { + param->options |= BT_LE_ADV_OPT_NO_2M; + } else if (!strcmp(arg, "anon")) { + param->options |= BT_LE_ADV_OPT_ANONYMOUS; + } else if (!strcmp(arg, "tx-power")) { + param->options |= BT_LE_ADV_OPT_USE_TX_POWER; + } else if (!strcmp(arg, "scan-reports")) { + param->options |= BT_LE_ADV_OPT_NOTIFY_SCAN_REQ; + } else if (!strcmp(arg, "wl")) { + param->options |= BT_LE_ADV_OPT_FILTER_SCAN_REQ; + param->options |= BT_LE_ADV_OPT_FILTER_CONN; + } else if (!strcmp(arg, "wl-scan")) { + param->options |= BT_LE_ADV_OPT_FILTER_SCAN_REQ; + } else if (!strcmp(arg, "wl-conn")) { + param->options |= BT_LE_ADV_OPT_FILTER_CONN; + } else if (!strcmp(arg, "identity")) { + param->options |= BT_LE_ADV_OPT_USE_IDENTITY; + } else { + return false; + } + } + + param->id = selected_id; + param->sid = 0; + param->interval_min = BT_GAP_ADV_FAST_INT_MIN_2; + param->interval_max = BT_GAP_ADV_FAST_INT_MAX_2; + + return true; +} + +static int cmd_adv_create(const struct shell *shell, size_t argc, char *argv[]) +{ + struct bt_le_adv_param param; + struct bt_le_ext_adv *adv; + u8_t adv_index; + int err; + + if (!adv_param_parse(argc, argv, ¶m)) { + shell_help(shell); + return -ENOEXEC; + } + + err = bt_le_ext_adv_create(¶m, &adv_callbacks, &adv); + if (err) { + shell_error(shell, "Failed to create advertiser set (%d)", err); + return -ENOEXEC; + } + + adv_index = bt_le_ext_adv_get_index(adv); + adv_sets[adv_index] = adv; + + shell_print(shell, "Created adv id: %d, adv: %p", adv_index, adv); + + return 0; +} + +static int cmd_adv_param(const struct shell *shell, size_t argc, char *argv[]) +{ + struct bt_le_ext_adv *adv = adv_sets[selected_adv]; + struct bt_le_adv_param param; + int err; + + if (!adv_param_parse(argc, argv, ¶m)) { + shell_help(shell); + return -ENOEXEC; + } + + err = bt_le_ext_adv_update_param(adv, ¶m); + if (err) { + shell_error(shell, "Failed to update advertiser set (%d)", err); + return -ENOEXEC; + } + + return 0; +} + +static int cmd_adv_data(const struct shell *shell, size_t argc, char *argv[]) +{ + struct bt_le_ext_adv *adv = adv_sets[selected_adv]; + struct bt_data ad[4]; + size_t ad_len = 0; + u8_t discov_data = (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR); + int err; + + if (!adv) { + return -EINVAL; + } + + for (size_t argn = 1; argn < argc; argn++) { + const char *arg = argv[argn]; + + if (!strcmp(arg, "discov")) { + ad[ad_len].type = BT_DATA_FLAGS; + ad[ad_len].data_len = sizeof(discov_data); + ad[ad_len].data = &discov_data; + ad_len++; + } else if (!strcmp(arg, "name")) { + const char *name = bt_get_name(); + + ad[ad_len].type = BT_DATA_NAME_COMPLETE; + ad[ad_len].data_len = strlen(name); + ad[ad_len].data = name; + ad_len++; + } else { + shell_help(shell); + return -ENOEXEC; + } + } + + err = bt_le_ext_adv_set_data(adv, ad, ad_len, NULL, 0); + if (err) { + shell_print(shell, "Failed to set advertising set data (%d)", + err); + return -ENOEXEC; + } + + return 0; +} + +static int cmd_adv_start(const struct shell *shell, size_t argc, char *argv[]) +{ + struct bt_le_ext_adv *adv = adv_sets[selected_adv]; + struct bt_le_ext_adv_start_param param; + u8_t num_events = 0; + s32_t timeout = 0; + int err; + + if (!adv) { + return -EINVAL; + } + + for (size_t argn = 1; argn < argc; argn++) { + const char *arg = argv[argn]; + + if (!strcmp(arg, "timeout")) { + if (++argn == argc) { + goto fail_show_help; + } + + timeout = strtoul(argv[argn], NULL, 16); + } + + if (!strcmp(arg, "num_events")) { + if (++argn == argc) { + goto fail_show_help; + } + + num_events = strtoul(argv[argn], NULL, 16); + } + } + + param.timeout = timeout; + param.num_events = num_events; + + err = bt_le_ext_adv_start(adv, ¶m); + if (err) { + shell_print(shell, "Failed to start advertising set (%d)", err); + return -ENOEXEC; + } + + shell_print(shell, "Advertiser[%d] %p set started", selected_adv, adv); + return 0; + +fail_show_help: + shell_help(shell); + return -ENOEXEC; +} + +static int cmd_adv_stop(const struct shell *shell, size_t argc, char *argv[]) +{ + struct bt_le_ext_adv *adv = adv_sets[selected_adv]; + int err; + + if (!adv) { + return -EINVAL; + } + + err = bt_le_ext_adv_stop(adv); + if (err) { + shell_print(shell, "Failed to stop advertising set (%d)", err); + return -ENOEXEC; + } + + shell_print(shell, "Advertiser set stopped"); + return 0; +} + +static int cmd_adv_delete(const struct shell *shell, size_t argc, char *argv[]) +{ + struct bt_le_ext_adv *adv = adv_sets[selected_adv]; + int err; + + if (!adv) { + return -EINVAL; + } + + err = bt_le_ext_adv_delete(adv); + if (err) { + shell_error(ctx_shell, "Failed to delete advertiser set"); + return err; + } + + adv_sets[selected_adv] = NULL; + return 0; +} + +static int cmd_adv_select(const struct shell *shell, size_t argc, char *argv[]) +{ + if (argc == 2) { + u8_t id = strtol(argv[1], NULL, 10); + + if (!(id < ARRAY_SIZE(adv_sets))) { + return -EINVAL; + } + + selected_adv = id; + return 0; + } + + for (int i = 0; i < ARRAY_SIZE(adv_sets); i++) { + if (adv_sets[i]) { + shell_print(shell, "Advertiser[%d] %p", i, adv_sets[i]); + } + } + + return -ENOEXEC; +} + +static int cmd_adv_oob(const struct shell *shell, size_t argc, char *argv[]) +{ + struct bt_le_ext_adv *adv = adv_sets[selected_adv]; + int err; + + if (!adv) { + return -EINVAL; + } + + err = bt_le_ext_adv_oob_get_local(adv, &oob_local); + if (err) { + shell_error(shell, "OOB data failed"); + return err; + } + + print_le_oob(shell, &oob_local); + + return 0; +} + +static int cmd_adv_info(const struct shell *shell, size_t argc, char *argv[]) +{ + struct bt_le_ext_adv *adv = adv_sets[selected_adv]; + struct bt_le_ext_adv_info info; + int err; + + if (!adv) { + return -EINVAL; + } + + err = bt_le_ext_adv_get_info(adv, &info); + if (err) { + shell_error(shell, "OOB data failed"); + return err; + } + + shell_print(shell, "Advertiser[%d] %p", selected_adv, adv); + shell_print(shell, "Id: %d, TX power: %d dBm", info.id, info.tx_power); + + return 0; +} +#endif /* CONFIG_BT_EXT_ADV */ #endif /* CONFIG_BT_BROADCASTER */ #if defined(CONFIG_BT_CONN) @@ -731,6 +1139,7 @@ static int cmd_connect_le(const struct shell *shell, size_t argc, char *argv[]) int err; bt_addr_le_t addr; struct bt_conn *conn; + u32_t options = 0; err = bt_addr_le_from_str(argv[1], argv[2], &addr); if (err) { @@ -738,10 +1147,32 @@ static int cmd_connect_le(const struct shell *shell, size_t argc, char *argv[]) return err; } - conn = bt_conn_create_le(&addr, BT_LE_CONN_PARAM_DEFAULT); +#if defined(CONFIG_BT_EXT_ADV) + for (size_t argn = 3; argn < argc; argn++) { + const char *arg = argv[argn]; - if (!conn) { - shell_error(shell, "Connection failed"); + if (!strcmp(arg, "coded")) { + options |= BT_LE_CONN_OPT_CODED; + } else if (!strcmp(arg, "2m")) { + options |= BT_LE_CONN_OPT_2M; + } else if (!strcmp(arg, "no-1m")) { + options |= BT_LE_CONN_OPT_NO_1M; + } else { + shell_help(shell); + return SHELL_CMD_HELP_PRINTED; + } + } +#endif /* defined(CONFIG_BT_EXT_ADV) */ + + struct bt_conn_le_create_param *create_params = + BT_CONN_LE_CREATE_PARAM(options, + BT_GAP_SCAN_FAST_INTERVAL, + BT_GAP_SCAN_FAST_INTERVAL); + + err = bt_conn_le_create(&addr, create_params, BT_LE_CONN_PARAM_DEFAULT, + &conn); + if (err) { + shell_error(shell, "Connection failed (%d)", err); return -ENOEXEC; } else { @@ -1009,9 +1440,6 @@ static int cmd_chan_map(const struct shell *shell, size_t argc, char *argv[]) static int cmd_oob(const struct shell *shell, size_t argc, char *argv[]) { - char addr[BT_ADDR_LE_STR_LEN]; - char c[KEY_STR_LEN]; - char r[KEY_STR_LEN]; int err; err = bt_le_oob_get_local(selected_id, &oob_local); @@ -1020,15 +1448,7 @@ static int cmd_oob(const struct shell *shell, size_t argc, char *argv[]) return err; } - bt_addr_le_to_str(&oob_local.addr, addr, sizeof(addr)); - bin2hex(oob_local.le_sc_data.c, sizeof(oob_local.le_sc_data.c), c, - sizeof(c)); - bin2hex(oob_local.le_sc_data.r, sizeof(oob_local.le_sc_data.r), r, - sizeof(r)); - - shell_print(shell, "OOB data:"); - shell_print(shell, "%-26s %-32s %-32s", "addr", "random", "confirm"); - shell_print(shell, "%26s %32s %32s", addr, r, c); + print_le_oob(shell, &oob_local); return 0; } @@ -1647,10 +2067,32 @@ static int cmd_wl_connect(const struct shell *shell, size_t argc, char *argv[]) { int err; const char *action = argv[1]; + u32_t options = 0; - if (!strcmp(action, "on")) { - err = bt_conn_create_auto_le(BT_LE_CONN_PARAM_DEFAULT); +#if defined(CONFIG_BT_EXT_ADV) + for (size_t argn = 2; argn < argc; argn++) { + const char *arg = argv[argn]; + if (!strcmp(arg, "coded")) { + options |= BT_LE_CONN_OPT_CODED; + } else if (!strcmp(arg, "2m")) { + options |= BT_LE_CONN_OPT_2M; + } else if (!strcmp(arg, "no-1m")) { + options |= BT_LE_CONN_OPT_NO_1M; + } else { + shell_help(shell); + return SHELL_CMD_HELP_PRINTED; + } + } +#endif /* defined(CONFIG_BT_EXT_ADV) */ + struct bt_conn_le_create_param *create_params = + BT_CONN_LE_CREATE_PARAM(options, + BT_GAP_SCAN_FAST_INTERVAL, + BT_GAP_SCAN_FAST_WINDOW); + + if (!strcmp(action, "on")) { + err = bt_conn_le_create_auto(create_params, + BT_LE_CONN_PARAM_DEFAULT); if (err) { shell_error(shell, "Auto connect failed (err %d)", err); return err; @@ -1752,6 +2194,17 @@ static int cmd_auth_oob_tk(const struct shell *shell, size_t argc, char *argv[]) #define HELP_NONE "[none]" #define HELP_ADDR_LE " " +#if defined(CONFIG_BT_EXT_ADV) +#define EXT_ADV_SCAN_OPT " [coded] [no-1m]" +#define EXT_ADV_CONN_OPT " [coded] [2m] [no-1m]" +#define EXT_ADV_PARAM " " \ + "[ext-adv] [no-2m] [coded] " \ + "[whitelist: wl, wl-scan, wl-conn] [identity]" +#else +#define EXT_ADV_SCAN_OPT "" +#define EXT_ADV_CONN_OPT "" +#endif /* defined(CONFIG_BT_EXT_ADV) */ + SHELL_STATIC_SUBCMD_SET_CREATE(bt_cmds, SHELL_CMD_ARG(init, NULL, HELP_NONE, cmd_init, 1, 0), #if defined(CONFIG_BT_HCI) @@ -1765,8 +2218,9 @@ SHELL_STATIC_SUBCMD_SET_CREATE(bt_cmds, SHELL_CMD_ARG(name, NULL, "[name]", cmd_name, 1, 1), #if defined(CONFIG_BT_OBSERVER) SHELL_CMD_ARG(scan, NULL, - " [filter: dups, nodups] [wl]", - cmd_scan, 2, 2), + " [filter: dups, nodups] [wl]" + EXT_ADV_SCAN_OPT, + cmd_scan, 2, 4), #endif /* CONFIG_BT_OBSERVER */ #if defined(CONFIG_BT_BROADCASTER) SHELL_CMD_ARG(advertise, NULL, @@ -1777,10 +2231,24 @@ SHELL_STATIC_SUBCMD_SET_CREATE(bt_cmds, SHELL_CMD_ARG(directed-adv, NULL, HELP_ADDR_LE " [mode: low]", cmd_directed_adv, 3, 1), #endif /* CONFIG_BT_PERIPHERAL */ +#if defined(CONFIG_BT_EXT_ADV) + SHELL_CMD_ARG(adv-create, NULL, EXT_ADV_PARAM, cmd_adv_create, 2, 5), + SHELL_CMD_ARG(adv-param, NULL, EXT_ADV_PARAM, cmd_adv_param, 2, 5), + SHELL_CMD_ARG(adv-data, NULL, "", cmd_adv_data, + 1, 2), + SHELL_CMD_ARG(adv-start, NULL, "[timeout] [num_events]", cmd_adv_start, + 1, 2), + SHELL_CMD_ARG(adv-stop, NULL, "", cmd_adv_stop, 1, 0), + SHELL_CMD_ARG(adv-delete, NULL, "", cmd_adv_delete, 1, 0), + SHELL_CMD_ARG(adv-select, NULL, "[adv]", cmd_adv_select, 1, 1), + SHELL_CMD_ARG(adv-oob, NULL, HELP_NONE, cmd_adv_oob, 1, 0), + SHELL_CMD_ARG(adv-info, NULL, HELP_NONE, cmd_adv_info, 1, 0), +#endif #endif /* CONFIG_BT_BROADCASTER */ #if defined(CONFIG_BT_CONN) #if defined(CONFIG_BT_CENTRAL) - SHELL_CMD_ARG(connect, NULL, HELP_ADDR_LE, cmd_connect_le, 3, 0), + SHELL_CMD_ARG(connect, NULL, HELP_ADDR_LE EXT_ADV_CONN_OPT, + cmd_connect_le, 3, 3), #if !defined(CONFIG_BT_WHITELIST) SHELL_CMD_ARG(auto-conn, NULL, HELP_ADDR_LE, cmd_auto_conn, 3, 0), #endif /* !defined(CONFIG_BT_WHITELIST) */ @@ -1825,8 +2293,10 @@ SHELL_STATIC_SUBCMD_SET_CREATE(bt_cmds, SHELL_CMD_ARG(wl-add, NULL, HELP_ADDR_LE, cmd_wl_add, 3, 0), SHELL_CMD_ARG(wl-rem, NULL, HELP_ADDR_LE, cmd_wl_rem, 3, 0), SHELL_CMD_ARG(wl-clear, NULL, HELP_NONE, cmd_wl_clear, 1, 0), + #if defined(CONFIG_BT_CENTRAL) - SHELL_CMD_ARG(wl-connect, NULL, "", cmd_wl_connect, 2, 0), + SHELL_CMD_ARG(wl-connect, NULL, "" EXT_ADV_CONN_OPT, + cmd_wl_connect, 2, 3), #endif /* CONFIG_BT_CENTRAL */ #endif /* defined(CONFIG_BT_WHITELIST) */ #if defined(CONFIG_BT_FIXED_PASSKEY) diff --git a/subsys/net/l2/bluetooth/bluetooth.c b/subsys/net/l2/bluetooth/bluetooth.c index 401a17eee1cd..c89fe007602f 100644 --- a/subsys/net/l2/bluetooth/bluetooth.c +++ b/subsys/net/l2/bluetooth/bluetooth.c @@ -392,9 +392,8 @@ static int bt_connect(u32_t mgmt_request, struct net_if *iface, void *data, L2CAP_IPSP_PSM); } - default_conn = bt_conn_create_le(addr, BT_LE_CONN_PARAM_DEFAULT); - - return 0; + return bt_conn_le_create(addr, BT_CONN_LE_CREATE_CONN, + BT_LE_CONN_PARAM_DEFAULT, &default_conn); } static bool eir_found(u8_t type, const u8_t *data, u8_t data_len, @@ -474,7 +473,8 @@ static void device_found(const bt_addr_le_t *addr, s8_t rssi, u8_t type, struct net_buf_simple *ad) { /* We're only interested in connectable events */ - if (type == BT_LE_ADV_IND || type == BT_LE_ADV_DIRECT_IND) { + if (type == BT_GAP_ADV_TYPE_ADV_IND || + type == BT_GAP_ADV_TYPE_ADV_DIRECT_IND) { ad_parse(ad, eir_found, (void *)addr); } } diff --git a/tests/bluetooth/bsim_bt/bsim_test_app/src/test_connect1.c b/tests/bluetooth/bsim_bt/bsim_test_app/src/test_connect1.c index 7fa7785fd5b7..f8caea316705 100644 --- a/tests/bluetooth/bsim_bt/bsim_test_app/src/test_connect1.c +++ b/tests/bluetooth/bsim_bt/bsim_test_app/src/test_connect1.c @@ -291,6 +291,7 @@ static bool eir_found(struct bt_data *data, void *user_data) for (i = 0; i < data->data_len; i += sizeof(u16_t)) { struct bt_uuid *uuid; + struct bt_le_conn_param *param; u16_t u16; int err; @@ -306,8 +307,13 @@ static bool eir_found(struct bt_data *data, void *user_data) continue; } - default_conn = bt_conn_create_le(addr, - BT_LE_CONN_PARAM_DEFAULT); + param = BT_LE_CONN_PARAM_DEFAULT; + err = bt_conn_le_create(addr, BT_CONN_LE_CREATE_CONN, + param, &default_conn); + if (err) { + printk("Create conn failed (err %d)\n", err); + } + return false; } } @@ -325,7 +331,8 @@ static void device_found(const bt_addr_le_t *addr, s8_t rssi, u8_t type, dev, type, ad->len, rssi); /* We're only interested in connectable events */ - if (type == BT_LE_ADV_IND || type == BT_LE_ADV_DIRECT_IND) { + if (type == BT_GAP_ADV_TYPE_ADV_IND || + type == BT_GAP_ADV_TYPE_ADV_DIRECT_IND) { bt_data_parse(ad, eir_found, (void *)addr); } } diff --git a/tests/bluetooth/tester/src/gap.c b/tests/bluetooth/tester/src/gap.c index 4ad1474ca8a9..3a3c30862ebc 100644 --- a/tests/bluetooth/tester/src/gap.c +++ b/tests/bluetooth/tester/src/gap.c @@ -386,7 +386,7 @@ static void device_found(const bt_addr_le_t *addr, s8_t rssi, u8_t evtype, { /* if General/Limited Discovery - parse Advertising data to get flags */ if (!(discovery_flags & GAP_DISCOVERY_FLAG_LE_OBSERVE) && - (evtype != BT_LE_ADV_SCAN_RSP)) { + (evtype != BT_GAP_ADV_TYPE_SCAN_RSP)) { u8_t flags = get_ad_flags(ad); /* ignore non-discoverable devices */ @@ -404,7 +404,7 @@ static void device_found(const bt_addr_le_t *addr, s8_t rssi, u8_t evtype, } /* attach Scan Response data */ - if (evtype == BT_LE_ADV_SCAN_RSP) { + if (evtype == BT_GAP_ADV_TYPE_SCAN_RSP) { struct gap_device_found_ev *ev; bt_addr_le_t a; @@ -449,7 +449,8 @@ static void device_found(const bt_addr_le_t *addr, s8_t rssi, u8_t evtype, /* if Active Scan and scannable event - wait for Scan Response */ if ((discovery_flags & GAP_DISCOVERY_FLAG_LE_ACTIVE_SCAN) && - (evtype == BT_LE_ADV_IND || evtype == BT_LE_ADV_SCAN_IND)) { + (evtype == BT_GAP_ADV_TYPE_ADV_IND || + evtype == BT_GAP_ADV_TYPE_ADV_SCAN_IND)) { LOG_DBG("Waiting for scan response"); return; } @@ -506,11 +507,12 @@ static void connect(const u8_t *data, u16_t len) { struct bt_conn *conn; u8_t status; + int err; - conn = bt_conn_create_le((bt_addr_le_t *) data, - BT_LE_CONN_PARAM_DEFAULT); - if (!conn) { - LOG_ERR("Failed to create connection"); + err = bt_conn_le_create((bt_addr_le_t *) data, BT_CONN_LE_CREATE_CONN, + BT_LE_CONN_PARAM_DEFAULT, &conn); + if (err) { + LOG_ERR("Failed to create connection (%d)", err); status = BTP_STATUS_FAILED; goto rsp; }