diff --git a/include/bluetooth/bluetooth.h b/include/bluetooth/bluetooth.h index 03e7a8922e1..65bf6f754b0 100644 --- a/include/bluetooth/bluetooth.h +++ b/include/bluetooth/bluetooth.h @@ -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. * diff --git a/include/bluetooth/conn.h b/include/bluetooth/conn.h index a484d385996..fe4ce8d6695 100644 --- a/include/bluetooth/conn.h +++ b/include/bluetooth/conn.h @@ -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. diff --git a/include/bluetooth/hci.h b/include/bluetooth/hci.h index 8c3683d3b5e..64f8066cdda 100644 --- a/include/bluetooth/hci.h +++ b/include/bluetooth/hci.h @@ -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; diff --git a/subsys/bluetooth/host/Kconfig b/subsys/bluetooth/host/Kconfig index bc91eef532b..89c95634b8f 100644 --- a/subsys/bluetooth/host/Kconfig +++ b/subsys/bluetooth/host/Kconfig @@ -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 diff --git a/subsys/bluetooth/host/conn.c b/subsys/bluetooth/host/conn.c index c07229d6e66..b391ec7f1a2 100644 --- a/subsys/bluetooth/host/conn.c +++ b/subsys/bluetooth/host/conn.c @@ -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) diff --git a/subsys/bluetooth/host/hci_core.c b/subsys/bluetooth/host/hci_core.c index 9c741ceb724..e9d130b651b 100644 --- a/subsys/bluetooth/host/hci_core.c +++ b/subsys/bluetooth/host/hci_core.c @@ -193,6 +193,15 @@ static inline void handle_event(u8_t event, struct net_buf *buf, 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) 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_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) { struct net_buf *buf; @@ -790,12 +862,12 @@ static void hci_disconn_complete(struct net_buf *buf) 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)) { bt_conn_set_state(conn, BT_CONN_CONNECT_SCAN); bt_le_scan_update(false); } -#endif /* CONFIG_BT_CENTRAL */ +#endif /* defined(CONFIG_BT_CENTRAL) && !defined(CONFIG_BT_WHITELIST) */ 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); +#if !defined(CONFIG_BT_WHITELIST) /* Check if device is marked for autoconnect. */ if (atomic_test_bit(conn->flags, BT_CONN_AUTO_CONNECT)) { bt_conn_set_state(conn, BT_CONN_CONNECT_SCAN); } - +#endif /* !defined(CONFIG_BT_WHITELIST) */ 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); - 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 * object to keep host in sync with controller state */ 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) { 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 * 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; 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); 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.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)) { 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); } +#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) { struct net_buf *rsp; @@ -4111,24 +4231,27 @@ static int le_init(void) #if defined(CONFIG_BT_SMP) 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, &rsp); if (err) { return err; } - - rp = (void *)rsp->data; - - BT_DBG("Resolving List size %u", rp->rl_size); - - bt_dev.le.rl_size = rp->rl_size; - + le_read_resolving_list_size_complete(rsp); net_buf_unref(rsp); } #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(); } @@ -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->interval_min > param->interval_max || 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); } +#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 */ bt_dev.adv_id = 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; } - if (param->filter_dup != BT_HCI_LE_SCAN_FILTER_DUP_DISABLE && - param->filter_dup != BT_HCI_LE_SCAN_FILTER_DUP_ENABLE) { + if (param->filter_dup & + ~(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; } @@ -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, - 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); if (err) { diff --git a/subsys/bluetooth/host/hci_core.h b/subsys/bluetooth/host/hci_core.h index c28d4ace358..be6b1ff57ad 100644 --- a/subsys/bluetooth/host/hci_core.h +++ b/subsys/bluetooth/host/hci_core.h @@ -43,6 +43,8 @@ enum { BT_DEV_EXPLICIT_SCAN, BT_DEV_ACTIVE_SCAN, BT_DEV_SCAN_FILTER_DUP, + BT_DEV_SCAN_WL, + BT_DEV_AUTO_CONN, BT_DEV_RPA_VALID, @@ -83,6 +85,13 @@ struct bt_dev_le { */ u8_t rl_entries; #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) @@ -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_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); const bt_addr_le_t *bt_lookup_id_addr(u8_t id, const bt_addr_le_t *addr);