Skip to content
Permalink
Browse files

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>
  • Loading branch information...
joerchan authored and carlescufi committed Jul 22, 2019
1 parent d075c91 commit a463d117f666963fc2d4bb45b71b3ccdeae6e13b
@@ -288,6 +288,13 @@ enum {
* reading its Central Address Resolution characteristic.
*/
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. */
@@ -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,
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 */
struct bt_le_scan_param {
/** Scan type (BT_HCI_LE_SCAN_ACTIVE or BT_HCI_LE_SCAN_PASSIVE) */
u8_t type;

/** Duplicate filtering (BT_HCI_LE_SCAN_FILTER_DUP_ENABLE or
* BT_HCI_LE_SCAN_FILTER_DUP_DISABLE)
*/
/** Bit-field of scanning filter options. */
u8_t filter_dup;

/** Scan interval (N * 0.625 ms) */
@@ -420,7 +436,7 @@ struct bt_le_scan_param {
/** Helper to declare scan parameters inline
*
* @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 _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. */
#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_WINDOW)

@@ -444,7 +460,7 @@ struct bt_le_scan_param {
* (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, \
BT_HCI_LE_SCAN_FILTER_DUP_ENABLE, \
BT_LE_SCAN_FILTER_DUPLICATE, \
BT_GAP_SCAN_FAST_INTERVAL, \
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);

/** @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.
*
@@ -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.
* Returns a new reference that the the caller is responsible for managing.
*
* This uses the General Connection Establishment procedure.
*
* @param peer Remote address.
* @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,
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.
*
* This function enables/disables automatic connection initiation.
@@ -752,6 +752,11 @@ struct bt_hci_cp_le_set_random_address {
/* Needed in advertising reports when getting info about */
#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)
struct bt_hci_cp_le_set_adv_param {
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_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 {
u8_t scan_type;
u16_t interval;
@@ -816,6 +824,10 @@ struct bt_hci_cp_le_set_scan_enable {
} __packed;

#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 {
u16_t scan_interval;
u16_t scan_window;
@@ -177,6 +177,24 @@ config BT_SETTINGS_CCC_STORE_ON_WRITE
workqueue stack space.
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_HCI_ACL_FLOW_CONTROL
@@ -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
* starts advertising.
*/
#if !defined(CONFIG_BT_WHITELIST)
if (IS_ENABLED(CONFIG_BT_CENTRAL) &&
conn->type == BT_CONN_TYPE_LE) {
bt_le_set_auto_conn(&conn->le.dst, NULL);
}
#endif /* !defined(CONFIG_BT_WHITELIST) */

switch (conn->state) {
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;
}

#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,
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;
}

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);
if (conn) {
switch (conn->state) {
@@ -1985,6 +2134,7 @@ struct bt_conn *bt_conn_create_le(const bt_addr_le_t *peer,
return conn;
}

#if !defined(CONFIG_BT_WHITELIST)
int bt_le_set_auto_conn(const bt_addr_le_t *addr,
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;
}
#endif /* !defined(CONFIG_BT_WHITELIST) */
#endif /* CONFIG_BT_CENTRAL */

#if defined(CONFIG_BT_PERIPHERAL)

0 comments on commit a463d11

Please sign in to comment.
You can’t perform that action at this time.