Bluetooth: Host: Add whitelist support in Bluetooth Host API

Add whitelist support in the bluetooth host.
Supported features:
 - Advertising with whitelist on scan requests, connect request ,or both
 - Scanning with whitelist
 - Creating connections using a whitelist (Auto connection procedure).

Signed-off-by: Joakim Andersson <joakim.andersson@nordicsemi.no>
This commit is contained in:
Joakim Andersson 2019-07-22 13:13:38 +02:00 committed by Carles Cufí
commit a463d117f6
7 changed files with 449 additions and 26 deletions

View file

@ -288,6 +288,13 @@ enum {
* reading its Central Address Resolution characteristic. * reading its Central Address Resolution characteristic.
*/ */
BT_LE_ADV_OPT_DIR_ADDR_RPA = BIT(5), BT_LE_ADV_OPT_DIR_ADDR_RPA = BIT(5),
/* Use whitelist to filter devices that can request scan response data.
*/
BT_LE_ADV_OPT_FILTER_SCAN_REQ = BIT(6),
/* Use whitelist to filter devices that can connect. */
BT_LE_ADV_OPT_FILTER_CONN = BIT(7),
}; };
/** LE Advertising Parameters. */ /** LE Advertising Parameters. */
@ -400,14 +407,23 @@ int bt_le_adv_stop(void);
typedef void bt_le_scan_cb_t(const bt_addr_le_t *addr, s8_t rssi, 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); u8_t adv_type, struct net_buf_simple *buf);
enum {
/* Filter duplicates. */
BT_LE_SCAN_FILTER_DUPLICATE = BIT(0),
/* Filter using whitelist. */
BT_LE_SCAN_FILTER_WHITELIST = BIT(1),
/* Filter using extended filter policies. */
BT_LE_SCAN_FILTER_EXTENDED = BIT(2),
};
/** LE scan parameters */ /** LE scan parameters */
struct bt_le_scan_param { struct bt_le_scan_param {
/** Scan type (BT_HCI_LE_SCAN_ACTIVE or BT_HCI_LE_SCAN_PASSIVE) */ /** Scan type (BT_HCI_LE_SCAN_ACTIVE or BT_HCI_LE_SCAN_PASSIVE) */
u8_t type; u8_t type;
/** Duplicate filtering (BT_HCI_LE_SCAN_FILTER_DUP_ENABLE or /** Bit-field of scanning filter options. */
* BT_HCI_LE_SCAN_FILTER_DUP_DISABLE)
*/
u8_t filter_dup; u8_t filter_dup;
/** Scan interval (N * 0.625 ms) */ /** Scan interval (N * 0.625 ms) */
@ -420,7 +436,7 @@ struct bt_le_scan_param {
/** Helper to declare scan parameters inline /** Helper to declare scan parameters inline
* *
* @param _type Scan Type (BT_HCI_LE_SCAN_ACTIVE/BT_HCI_LE_SCAN_PASSIVE) * @param _type Scan Type (BT_HCI_LE_SCAN_ACTIVE/BT_HCI_LE_SCAN_PASSIVE)
* @param _filter Filter Duplicates * @param _filter Filter options
* @param _interval Scan Interval (N * 0.625 ms) * @param _interval Scan Interval (N * 0.625 ms)
* @param _window Scan Window (N * 0.625 ms) * @param _window Scan Window (N * 0.625 ms)
*/ */
@ -434,7 +450,7 @@ struct bt_le_scan_param {
/** Helper macro to enable active scanning to discover new devices. */ /** Helper macro to enable active scanning to discover new devices. */
#define BT_LE_SCAN_ACTIVE BT_LE_SCAN_PARAM(BT_HCI_LE_SCAN_ACTIVE, \ #define BT_LE_SCAN_ACTIVE BT_LE_SCAN_PARAM(BT_HCI_LE_SCAN_ACTIVE, \
BT_HCI_LE_SCAN_FILTER_DUP_ENABLE, \ BT_LE_SCAN_FILTER_DUPLICATE, \
BT_GAP_SCAN_FAST_INTERVAL, \ BT_GAP_SCAN_FAST_INTERVAL, \
BT_GAP_SCAN_FAST_WINDOW) BT_GAP_SCAN_FAST_WINDOW)
@ -444,7 +460,7 @@ struct bt_le_scan_param {
* (e.g., UUID) are known to be placed in Advertising Data. * (e.g., UUID) are known to be placed in Advertising Data.
*/ */
#define BT_LE_SCAN_PASSIVE BT_LE_SCAN_PARAM(BT_HCI_LE_SCAN_PASSIVE, \ #define BT_LE_SCAN_PASSIVE BT_LE_SCAN_PARAM(BT_HCI_LE_SCAN_PASSIVE, \
BT_HCI_LE_SCAN_FILTER_DUP_ENABLE, \ BT_LE_SCAN_FILTER_DUPLICATE, \
BT_GAP_SCAN_FAST_INTERVAL, \ BT_GAP_SCAN_FAST_INTERVAL, \
BT_GAP_SCAN_FAST_WINDOW) BT_GAP_SCAN_FAST_WINDOW)
@ -470,6 +486,48 @@ int bt_le_scan_start(const struct bt_le_scan_param *param, bt_le_scan_cb_t cb);
*/ */
int bt_le_scan_stop(void); int bt_le_scan_stop(void);
/** @brief Add device (LE) to whitelist.
*
* Add peer device LE address to the whitelist.
*
* @note The whitelist cannot be modified when an LE role is using
* the whitelist, i.e advertiser or scanner using a whitelist or automatic
* connecting to devices using whitelist.
*
* @param addr Bluetooth LE identity address.
*
* @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_whitelist_add(const bt_addr_le_t *addr);
/** @brief Remove device (LE) from whitelist.
*
* Remove peer device LE address from the whitelist.
*
* @note The whitelist cannot be modified when an LE role is using
* the whitelist, i.e advertiser or scanner using a whitelist or automatic
* connecting to devices using whitelist.
*
* @param addr Bluetooth LE identity address.
*
* @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_whitelist_rem(const bt_addr_le_t *addr);
/** @brief Clear whitelist.
*
* Clear all devices from the whitelist.
*
* @note The whitelist cannot be modified when an LE role is using
* the whitelist, i.e advertiser or scanner using a whitelist or automatic
* connecting to devices using whitelist.
*
* @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_whitelist_clear(void);
/** @brief Set (LE) channel map. /** @brief Set (LE) channel map.
* *

View file

@ -209,6 +209,8 @@ int bt_conn_disconnect(struct bt_conn *conn, u8_t reason);
* Allows initiate new LE link to remote peer using its address. * Allows initiate new LE link to remote peer using its address.
* Returns a new reference that the the caller is responsible for managing. * Returns a new reference that the the caller is responsible for managing.
* *
* This uses the General Connection Establishment procedure.
*
* @param peer Remote address. * @param peer Remote address.
* @param param Initial connection parameters. * @param param Initial connection parameters.
* *
@ -217,6 +219,22 @@ int bt_conn_disconnect(struct bt_conn *conn, u8_t reason);
struct bt_conn *bt_conn_create_le(const bt_addr_le_t *peer, 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 *param);
/** @brief Automatically connect to remote devices in whitelist.
*
* This uses the Auto Connection Establishment procedure.
*
* @param param Initial connection parameters.
*
* @return Zero on success or (negative) error code on failure.
*/
int bt_conn_create_auto_le(const struct bt_le_conn_param *param);
/** @brief Stop automatic connect creation.
*
* @return Zero on success or (negative) error code on failure.
*/
int bt_conn_create_auto_stop(void);
/** @brief Automatically connect to remote device if it's in range. /** @brief Automatically connect to remote device if it's in range.
* *
* This function enables/disables automatic connection initiation. * This function enables/disables automatic connection initiation.

View file

@ -752,6 +752,11 @@ struct bt_hci_cp_le_set_random_address {
/* Needed in advertising reports when getting info about */ /* Needed in advertising reports when getting info about */
#define BT_LE_ADV_SCAN_RSP 0x04 #define BT_LE_ADV_SCAN_RSP 0x04
#define BT_LE_ADV_FP_NO_WHITELIST 0x00
#define BT_LE_ADV_FP_WHITELIST_SCAN_REQ 0x01
#define BT_LE_ADV_FP_WHITELIST_CONN_IND 0x02
#define BT_LE_ADV_FP_WHITELIST_BOTH 0x03
#define BT_HCI_OP_LE_SET_ADV_PARAM BT_OP(BT_OGF_LE, 0x0006) #define BT_HCI_OP_LE_SET_ADV_PARAM BT_OP(BT_OGF_LE, 0x0006)
struct bt_hci_cp_le_set_adv_param { struct bt_hci_cp_le_set_adv_param {
u16_t min_interval; u16_t min_interval;
@ -794,6 +799,9 @@ struct bt_hci_cp_le_set_adv_enable {
#define BT_HCI_LE_SCAN_PASSIVE 0x00 #define BT_HCI_LE_SCAN_PASSIVE 0x00
#define BT_HCI_LE_SCAN_ACTIVE 0x01 #define BT_HCI_LE_SCAN_ACTIVE 0x01
#define BT_HCI_LE_SCAN_FP_NO_WHITELIST 0x00
#define BT_HCI_LE_SCAN_FP_USE_WHITELIST 0x01
struct bt_hci_cp_le_set_scan_param { struct bt_hci_cp_le_set_scan_param {
u8_t scan_type; u8_t scan_type;
u16_t interval; u16_t interval;
@ -816,6 +824,10 @@ struct bt_hci_cp_le_set_scan_enable {
} __packed; } __packed;
#define BT_HCI_OP_LE_CREATE_CONN BT_OP(BT_OGF_LE, 0x000d) #define BT_HCI_OP_LE_CREATE_CONN BT_OP(BT_OGF_LE, 0x000d)
#define BT_HCI_LE_CREATE_CONN_FP_DIRECT 0x00
#define BT_HCI_LE_CREATE_CONN_FP_WHITELIST 0x01
struct bt_hci_cp_le_create_conn { struct bt_hci_cp_le_create_conn {
u16_t scan_interval; u16_t scan_interval;
u16_t scan_window; u16_t scan_window;

View file

@ -177,6 +177,24 @@ config BT_SETTINGS_CCC_STORE_ON_WRITE
workqueue stack space. workqueue stack space.
endif # BT_SETTINGS endif # BT_SETTINGS
config BT_WHITELIST
bool "Enable whitelist support"
help
This option enables the whitelist API. This takes advantage of the
whitelisting feature of a BLE controller.
The whitelist is a global list and the same whitelist is used
by both scanner and advertiser. The whitelist cannot be modified while
it is in use.
An Advertiser can whitelist which peers can connect or request scan
response data.
A scanner can whitelist advertiser for which it will generate
advertising reports.
Connections can be established automatically for whitelisted peers.
This options deprecates the bt_le_set_auto_conn API in favor of the
bt_conn_create_aute_le API.
if BT_CONN if BT_CONN
if BT_HCI_ACL_FLOW_CONTROL if BT_HCI_ACL_FLOW_CONTROL

View file

@ -1871,10 +1871,12 @@ int bt_conn_disconnect(struct bt_conn *conn, u8_t reason)
* and we could send LE Create Connection as soon as the remote * and we could send LE Create Connection as soon as the remote
* starts advertising. * starts advertising.
*/ */
#if !defined(CONFIG_BT_WHITELIST)
if (IS_ENABLED(CONFIG_BT_CENTRAL) && if (IS_ENABLED(CONFIG_BT_CENTRAL) &&
conn->type == BT_CONN_TYPE_LE) { conn->type == BT_CONN_TYPE_LE) {
bt_le_set_auto_conn(&conn->le.dst, NULL); bt_le_set_auto_conn(&conn->le.dst, NULL);
} }
#endif /* !defined(CONFIG_BT_WHITELIST) */
switch (conn->state) { switch (conn->state) {
case BT_CONN_CONNECT_SCAN: case BT_CONN_CONNECT_SCAN:
@ -1927,6 +1929,148 @@ static void bt_conn_set_param_le(struct bt_conn *conn,
conn->le.timeout = param->timeout; conn->le.timeout = param->timeout;
} }
#if defined(CONFIG_BT_WHITELIST)
int bt_le_whitelist_add(const bt_addr_le_t *addr)
{
struct bt_hci_cp_le_add_dev_to_wl *cp;
struct net_buf *buf;
int err;
if (!(bt_dev.le.wl_entries < bt_dev.le.wl_size)) {
return -ENOMEM;
}
buf = bt_hci_cmd_create(BT_HCI_OP_LE_ADD_DEV_TO_WL, sizeof(*cp));
if (!buf) {
return -ENOBUFS;
}
cp = net_buf_add(buf, sizeof(*cp));
bt_addr_le_copy(&cp->addr, addr);
err = bt_hci_cmd_send_sync(BT_HCI_OP_LE_ADD_DEV_TO_WL, buf, NULL);
if (err) {
BT_ERR("Failed to add device to whitelist");
return err;
}
bt_dev.le.wl_entries++;
return 0;
}
int bt_le_whitelist_rem(const bt_addr_le_t *addr)
{
struct bt_hci_cp_le_rem_dev_from_wl *cp;
struct net_buf *buf;
int err;
buf = bt_hci_cmd_create(BT_HCI_OP_LE_REM_DEV_FROM_WL, sizeof(*cp));
if (!buf) {
return -ENOBUFS;
}
cp = net_buf_add(buf, sizeof(*cp));
bt_addr_le_copy(&cp->addr, addr);
err = bt_hci_cmd_send_sync(BT_HCI_OP_LE_REM_DEV_FROM_WL, buf, NULL);
if (err) {
BT_ERR("Failed to remove device from whitelist");
return err;
}
bt_dev.le.wl_entries--;
return 0;
}
int bt_le_whitelist_clear(void)
{
int err = bt_hci_cmd_send_sync(BT_HCI_OP_LE_CLEAR_WL, NULL, NULL);
if (err) {
BT_ERR("Failed to clear whitelist");
return err;
}
bt_dev.le.wl_entries = 0;
return 0;
}
int bt_conn_create_auto_le(const struct bt_le_conn_param *param)
{
struct bt_conn *conn;
int err;
if (!atomic_test_bit(bt_dev.flags, BT_DEV_READY)) {
return -EINVAL;
}
if (!bt_le_conn_params_valid(param)) {
return -EINVAL;
}
if (atomic_test_bit(bt_dev.flags, BT_DEV_EXPLICIT_SCAN)) {
return -EINVAL;
}
if (atomic_test_bit(bt_dev.flags, BT_DEV_AUTO_CONN)) {
return -EALREADY;
}
if (!bt_dev.le.wl_entries) {
return -EINVAL;
}
/* Don't start initiator if we have general discovery procedure. */
conn = bt_conn_lookup_state_le(NULL, BT_CONN_CONNECT_SCAN);
if (conn) {
bt_conn_unref(conn);
return -EINVAL;
}
/* Don't start initiator if we have direct discovery procedure. */
conn = bt_conn_lookup_state_le(NULL, BT_CONN_CONNECT);
if (conn) {
bt_conn_unref(conn);
return -EINVAL;
}
err = bt_le_auto_conn(param);
if (err) {
BT_ERR("Failed to start whitelist scan");
return err;
}
atomic_set_bit(bt_dev.flags, BT_DEV_AUTO_CONN);
return 0;
}
int bt_conn_create_auto_stop(void)
{
if (!atomic_test_bit(bt_dev.flags, BT_DEV_READY)) {
return -EINVAL;
}
if (!atomic_test_bit(bt_dev.flags, BT_DEV_AUTO_CONN)) {
return -EINVAL;
}
int err = bt_hci_cmd_send_sync(BT_HCI_OP_LE_CREATE_CONN_CANCEL, NULL,
NULL);
atomic_clear_bit(bt_dev.flags, BT_DEV_AUTO_CONN);
if (err) {
BT_ERR("Failed to stop initiator");
return err;
}
return 0;
}
#endif /* defined(CONFIG_BT_WHITELIST) */
struct bt_conn *bt_conn_create_le(const bt_addr_le_t *peer, 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 *param)
{ {
@ -1945,6 +2089,11 @@ struct bt_conn *bt_conn_create_le(const bt_addr_le_t *peer,
return NULL; return NULL;
} }
if (IS_ENABLED(CONFIG_BT_WHITELIST) &&
atomic_test_bit(bt_dev.flags, BT_DEV_AUTO_CONN)) {
return NULL;
}
conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, peer); conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, peer);
if (conn) { if (conn) {
switch (conn->state) { switch (conn->state) {
@ -1985,6 +2134,7 @@ struct bt_conn *bt_conn_create_le(const bt_addr_le_t *peer,
return conn; return conn;
} }
#if !defined(CONFIG_BT_WHITELIST)
int bt_le_set_auto_conn(const bt_addr_le_t *addr, int bt_le_set_auto_conn(const bt_addr_le_t *addr,
const struct bt_le_conn_param *param) const struct bt_le_conn_param *param)
{ {
@ -2034,6 +2184,7 @@ int bt_le_set_auto_conn(const bt_addr_le_t *addr,
return 0; return 0;
} }
#endif /* !defined(CONFIG_BT_WHITELIST) */
#endif /* CONFIG_BT_CENTRAL */ #endif /* CONFIG_BT_CENTRAL */
#if defined(CONFIG_BT_PERIPHERAL) #if defined(CONFIG_BT_PERIPHERAL)

View file

@ -193,6 +193,15 @@ static inline void handle_event(u8_t event, struct net_buf *buf,
buf->len, bt_hex(buf->data, buf->len)); buf->len, bt_hex(buf->data, buf->len));
} }
static inline bool is_wl_empty(void)
{
#if defined(CONFIG_BT_WHITELIST)
return !bt_dev.le.wl_entries;
#else
return true;
#endif /* defined(CONFIG_BT_WHITELIST) */
}
#if defined(CONFIG_BT_HCI_ACL_FLOW_CONTROL) #if defined(CONFIG_BT_HCI_ACL_FLOW_CONTROL)
static void report_completed_packet(struct net_buf *buf) static void report_completed_packet(struct net_buf *buf)
{ {
@ -686,6 +695,69 @@ static void hci_num_completed_packets(struct net_buf *buf)
} }
#if defined(CONFIG_BT_CENTRAL) #if defined(CONFIG_BT_CENTRAL)
#if defined(CONFIG_BT_WHITELIST)
int bt_le_auto_conn(const struct bt_le_conn_param *conn_param)
{
struct net_buf *buf;
struct bt_hci_cp_le_create_conn *cp;
u8_t own_addr_type;
int err;
if (atomic_test_bit(bt_dev.flags, BT_DEV_SCANNING)) {
err = set_le_scan_enable(BT_HCI_LE_SCAN_DISABLE);
if (err) {
return err;
}
}
if (IS_ENABLED(CONFIG_BT_PRIVACY)) {
err = le_set_private_addr(BT_ID_DEFAULT);
if (err) {
return err;
}
if (BT_FEAT_LE_PRIVACY(bt_dev.le.features)) {
own_addr_type = BT_HCI_OWN_ADDR_RPA_OR_RANDOM;
} else {
own_addr_type = BT_ADDR_LE_RANDOM;
}
} else {
const bt_addr_le_t *addr = &bt_dev.id_addr[BT_ID_DEFAULT];
/* If Static Random address is used as Identity address we
* need to restore it before creating connection. Otherwise
* NRPA used for active scan could be used for connection.
*/
if (addr->type == BT_ADDR_LE_RANDOM) {
set_random_address(&addr->a);
}
own_addr_type = addr->type;
}
buf = bt_hci_cmd_create(BT_HCI_OP_LE_CREATE_CONN, sizeof(*cp));
if (!buf) {
return -ENOBUFS;
}
cp = net_buf_add(buf, sizeof(*cp));
(void)memset(cp, 0, sizeof(*cp));
cp->filter_policy = BT_HCI_LE_CREATE_CONN_FP_WHITELIST;
cp->own_addr_type = own_addr_type;
/* User Initiated procedure use fast scan parameters. */
cp->scan_interval = sys_cpu_to_le16(BT_GAP_SCAN_FAST_INTERVAL);
cp->scan_window = sys_cpu_to_le16(BT_GAP_SCAN_FAST_WINDOW);
cp->conn_interval_min = sys_cpu_to_le16(conn_param->interval_min);
cp->conn_interval_max = sys_cpu_to_le16(conn_param->interval_max);
cp->conn_latency = sys_cpu_to_le16(conn_param->latency);
cp->supervision_timeout = sys_cpu_to_le16(conn_param->timeout);
return bt_hci_cmd_send_sync(BT_HCI_OP_LE_CREATE_CONN, buf, NULL);
}
#endif /* defined(CONFIG_BT_WHITELIST) */
static int hci_le_create_conn(const struct bt_conn *conn) static int hci_le_create_conn(const struct bt_conn *conn)
{ {
struct net_buf *buf; struct net_buf *buf;
@ -790,12 +862,12 @@ static void hci_disconn_complete(struct net_buf *buf)
return; return;
} }
#if defined(CONFIG_BT_CENTRAL) #if defined(CONFIG_BT_CENTRAL) && !defined(CONFIG_BT_WHITELIST)
if (atomic_test_bit(conn->flags, BT_CONN_AUTO_CONNECT)) { if (atomic_test_bit(conn->flags, BT_CONN_AUTO_CONNECT)) {
bt_conn_set_state(conn, BT_CONN_CONNECT_SCAN); bt_conn_set_state(conn, BT_CONN_CONNECT_SCAN);
bt_le_scan_update(false); bt_le_scan_update(false);
} }
#endif /* CONFIG_BT_CENTRAL */ #endif /* defined(CONFIG_BT_CENTRAL) && !defined(CONFIG_BT_WHITELIST) */
bt_conn_unref(conn); bt_conn_unref(conn);
@ -996,13 +1068,14 @@ static void enh_conn_complete(struct bt_hci_evt_le_enh_conn_complete *evt)
*/ */
bt_conn_set_state(conn, BT_CONN_DISCONNECTED); bt_conn_set_state(conn, BT_CONN_DISCONNECTED);
#if !defined(CONFIG_BT_WHITELIST)
/* Check if device is marked for autoconnect. */ /* Check if device is marked for autoconnect. */
if (atomic_test_bit(conn->flags, if (atomic_test_bit(conn->flags,
BT_CONN_AUTO_CONNECT)) { BT_CONN_AUTO_CONNECT)) {
bt_conn_set_state(conn, bt_conn_set_state(conn,
BT_CONN_CONNECT_SCAN); BT_CONN_CONNECT_SCAN);
} }
#endif /* !defined(CONFIG_BT_WHITELIST) */
goto done; goto done;
} }
} }
@ -1028,14 +1101,24 @@ static void enh_conn_complete(struct bt_hci_evt_le_enh_conn_complete *evt)
conn = find_pending_connect(&id_addr); conn = find_pending_connect(&id_addr);
if (evt->role == BT_CONN_ROLE_SLAVE) { if (IS_ENABLED(CONFIG_BT_PERIPHERAL) &&
evt->role == BT_HCI_ROLE_SLAVE) {
/* /*
* clear advertising even if we are not able to add connection * clear advertising even if we are not able to add connection
* object to keep host in sync with controller state * object to keep host in sync with controller state
*/ */
atomic_clear_bit(bt_dev.flags, BT_DEV_ADVERTISING); atomic_clear_bit(bt_dev.flags, BT_DEV_ADVERTISING);
/* only for slave we may need to add new connection */ /* for slave we may need to add new connection */
if (!conn) {
conn = bt_conn_add_le(&id_addr);
}
}
if (IS_ENABLED(CONFIG_BT_CENTRAL) &&
IS_ENABLED(CONFIG_BT_WHITELIST) &&
evt->role == BT_HCI_ROLE_MASTER) {
/* for whitelist initiator me may need to add new connection. */
if (!conn) { if (!conn) {
conn = bt_conn_add_le(&id_addr); conn = bt_conn_add_le(&id_addr);
} }
@ -1059,7 +1142,8 @@ static void enh_conn_complete(struct bt_hci_evt_le_enh_conn_complete *evt)
* or responder address. Only slave needs to be updated. For master all * or responder address. Only slave needs to be updated. For master all
* was set during outgoing connection creation. * was set during outgoing connection creation.
*/ */
if (conn->role == BT_HCI_ROLE_SLAVE) { if (IS_ENABLED(CONFIG_BT_PERIPHERAL) &&
conn->role == BT_HCI_ROLE_SLAVE) {
conn->id = bt_dev.adv_id; conn->id = bt_dev.adv_id;
bt_addr_le_copy(&conn->le.init_addr, &peer_addr); bt_addr_le_copy(&conn->le.init_addr, &peer_addr);
@ -1086,7 +1170,14 @@ static void enh_conn_complete(struct bt_hci_evt_le_enh_conn_complete *evt)
} }
} }
if (conn->role == BT_HCI_ROLE_MASTER) { if (IS_ENABLED(CONFIG_BT_CENTRAL) &&
conn->role == BT_HCI_ROLE_MASTER) {
if (IS_ENABLED(CONFIG_BT_WHITELIST) &&
atomic_test_bit(bt_dev.flags, BT_DEV_AUTO_CONN)) {
conn->id = BT_ID_DEFAULT;
atomic_clear_bit(bt_dev.flags, BT_DEV_AUTO_CONN);
}
bt_addr_le_copy(&conn->le.resp_addr, &peer_addr); bt_addr_le_copy(&conn->le.resp_addr, &peer_addr);
if (IS_ENABLED(CONFIG_BT_PRIVACY)) { if (IS_ENABLED(CONFIG_BT_PRIVACY)) {
@ -3274,7 +3365,13 @@ static int start_le_scan(u8_t scan_type, u16_t interval, u16_t window)
*/ */
set_param.interval = sys_cpu_to_le16(interval); set_param.interval = sys_cpu_to_le16(interval);
set_param.window = sys_cpu_to_le16(window); set_param.window = sys_cpu_to_le16(window);
set_param.filter_policy = 0x00;
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)) { if (IS_ENABLED(CONFIG_BT_PRIVACY)) {
err = le_set_private_addr(BT_ID_DEFAULT); err = le_set_private_addr(BT_ID_DEFAULT);
@ -3878,6 +3975,29 @@ static void le_read_supp_states_complete(struct net_buf *buf)
bt_dev.le.states = sys_get_le64(rp->le_states); bt_dev.le.states = sys_get_le64(rp->le_states);
} }
#if defined(CONFIG_BT_SMP)
static void le_read_resolving_list_size_complete(struct net_buf *buf)
{
struct bt_hci_rp_le_read_rl_size *rp = (void *)buf->data;
BT_DBG("Resolving List size %u", rp->rl_size);
bt_dev.le.rl_size = rp->rl_size;
}
#endif /* defined(CONFIG_BT_SMP) */
#if defined(CONFIG_BT_WHITELIST)
static void le_read_wl_size_complete(struct net_buf *buf)
{
struct bt_hci_rp_le_read_wl_size *rp =
(struct bt_hci_rp_le_read_wl_size *)buf->data;
BT_DBG("Whitelist size %u", rp->wl_size);
bt_dev.le.wl_size = rp->wl_size;
}
#endif
static int common_init(void) static int common_init(void)
{ {
struct net_buf *rsp; struct net_buf *rsp;
@ -4111,24 +4231,27 @@ static int le_init(void)
#if defined(CONFIG_BT_SMP) #if defined(CONFIG_BT_SMP)
if (BT_FEAT_LE_PRIVACY(bt_dev.le.features)) { if (BT_FEAT_LE_PRIVACY(bt_dev.le.features)) {
struct bt_hci_rp_le_read_rl_size *rp;
err = bt_hci_cmd_send_sync(BT_HCI_OP_LE_READ_RL_SIZE, NULL, err = bt_hci_cmd_send_sync(BT_HCI_OP_LE_READ_RL_SIZE, NULL,
&rsp); &rsp);
if (err) { if (err) {
return err; return err;
} }
le_read_resolving_list_size_complete(rsp);
rp = (void *)rsp->data;
BT_DBG("Resolving List size %u", rp->rl_size);
bt_dev.le.rl_size = rp->rl_size;
net_buf_unref(rsp); net_buf_unref(rsp);
} }
#endif #endif
#if defined(CONFIG_BT_WHITELIST)
err = bt_hci_cmd_send_sync(BT_HCI_OP_LE_READ_WL_SIZE, NULL,
&rsp);
if (err) {
return err;
}
le_read_wl_size_complete(rsp);
net_buf_unref(rsp);
#endif /* defined(CONFIG_BT_WHITELIST) */
return le_set_event_mask(); return le_set_event_mask();
} }
@ -5299,6 +5422,13 @@ static bool valid_adv_param(const struct bt_le_adv_param *param, bool dir_adv)
} }
} }
if (is_wl_empty() &&
((param->options & BT_LE_ADV_OPT_FILTER_SCAN_REQ) ||
(param->options & BT_LE_ADV_OPT_FILTER_CONN))) {
return false;
}
if ((param->options & BT_LE_ADV_OPT_DIR_MODE_LOW_DUTY) || !dir_adv) { if ((param->options & BT_LE_ADV_OPT_DIR_MODE_LOW_DUTY) || !dir_adv) {
if (param->interval_min > param->interval_max || if (param->interval_min > param->interval_max ||
param->interval_min < 0x0020 || param->interval_min < 0x0020 ||
@ -5441,6 +5571,21 @@ int bt_le_adv_start_internal(const struct bt_le_adv_param *param,
atomic_clear_bit(bt_dev.flags, BT_DEV_RPA_VALID); 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;
} else {
#else
{
#endif /* defined(CONFIG_BT_WHITELIST) */
set_param.filter_policy = BT_LE_ADV_FP_NO_WHITELIST;
}
/* Set which local identity address we're advertising with */ /* Set which local identity address we're advertising with */
bt_dev.adv_id = param->id; bt_dev.adv_id = param->id;
id_addr = &bt_dev.id_addr[param->id]; id_addr = &bt_dev.id_addr[param->id];
@ -5595,8 +5740,13 @@ static bool valid_le_scan_param(const struct bt_le_scan_param *param)
return false; return false;
} }
if (param->filter_dup != BT_HCI_LE_SCAN_FILTER_DUP_DISABLE && if (param->filter_dup &
param->filter_dup != BT_HCI_LE_SCAN_FILTER_DUP_ENABLE) { ~(BT_LE_SCAN_FILTER_DUPLICATE | BT_LE_SCAN_FILTER_WHITELIST)) {
return false;
}
if (is_wl_empty() &&
param->filter_dup & BT_LE_SCAN_FILTER_WHITELIST) {
return false; return false;
} }
@ -5642,7 +5792,12 @@ 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, atomic_set_bit_to(bt_dev.flags, BT_DEV_SCAN_FILTER_DUP,
param->filter_dup); param->filter_dup & BT_LE_SCAN_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);
#endif /* defined(CONFIG_BT_WHITELIST) */
err = start_le_scan(param->type, param->interval, param->window); err = start_le_scan(param->type, param->interval, param->window);
if (err) { if (err) {

View file

@ -43,6 +43,8 @@ enum {
BT_DEV_EXPLICIT_SCAN, BT_DEV_EXPLICIT_SCAN,
BT_DEV_ACTIVE_SCAN, BT_DEV_ACTIVE_SCAN,
BT_DEV_SCAN_FILTER_DUP, BT_DEV_SCAN_FILTER_DUP,
BT_DEV_SCAN_WL,
BT_DEV_AUTO_CONN,
BT_DEV_RPA_VALID, BT_DEV_RPA_VALID,
@ -83,6 +85,13 @@ struct bt_dev_le {
*/ */
u8_t rl_entries; u8_t rl_entries;
#endif /* CONFIG_BT_SMP */ #endif /* CONFIG_BT_SMP */
#if defined(CONFIG_BT_WHITELIST)
/* Size of the controller whitelist. */
u8_t wl_size;
/* Number of entries in the resolving list. */
u8_t wl_entries;
#endif /* CONFIG_BT_WHITELIST */
}; };
#if defined(CONFIG_BT_BREDR) #if defined(CONFIG_BT_BREDR)
@ -185,6 +194,8 @@ bool bt_le_conn_params_valid(const struct bt_le_conn_param *param);
int bt_le_scan_update(bool fast_scan); int bt_le_scan_update(bool fast_scan);
int bt_le_auto_conn(const struct bt_le_conn_param *conn_param);
bool bt_addr_le_is_bonded(u8_t id, const bt_addr_le_t *addr); bool bt_addr_le_is_bonded(u8_t id, const bt_addr_le_t *addr);
const bt_addr_le_t *bt_lookup_id_addr(u8_t id, const bt_addr_le_t *addr); const bt_addr_le_t *bt_lookup_id_addr(u8_t id, const bt_addr_le_t *addr);