From 99662c63bc4c685f3fa00ceb6b466908ffbe55c9 Mon Sep 17 00:00:00 2001 From: Joakim Andersson Date: Sun, 29 Dec 2019 18:47:53 +0100 Subject: [PATCH] Bluetooth: host: Handle starting roles with different random address Handle starting of advertiser and scanner or initiator when advertiser is using a different identity than the default identity to generate the random resolvable address in the controller. We need to handle this only for the privacy case because the random address is set in the RPA timeout handler and not from the API. When privacy is disabled we can return error code from the LE Set Random Address HCI command instead. Signed-off-by: Joakim Andersson --- subsys/bluetooth/host/conn.c | 12 +++++ subsys/bluetooth/host/hci_core.c | 82 ++++++++++++++++++++++++++++++++ subsys/bluetooth/host/hci_core.h | 2 + 3 files changed, 96 insertions(+) diff --git a/subsys/bluetooth/host/conn.c b/subsys/bluetooth/host/conn.c index f027f98162c..a3236ef8d4a 100644 --- a/subsys/bluetooth/host/conn.c +++ b/subsys/bluetooth/host/conn.c @@ -2126,6 +2126,10 @@ int bt_conn_create_auto_le(const struct bt_le_conn_param *param) return -EINVAL; } + if (!bt_le_scan_random_addr_check()) { + return -EINVAL; + } + conn = bt_conn_add_le(BT_ID_DEFAULT, BT_ADDR_LE_NONE); if (!conn) { return -ENOMEM; @@ -2204,6 +2208,10 @@ struct bt_conn *bt_conn_create_le(const bt_addr_le_t *peer, return NULL; } + if (!bt_le_scan_random_addr_check()) { + return NULL; + } + conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, peer); if (conn) { /* Connection object already exists. @@ -2272,6 +2280,10 @@ int bt_le_set_auto_conn(const bt_addr_le_t *addr, return -EINVAL; } + if (!bt_le_scan_random_addr_check()) { + return -EINVAL; + } + /* Only default identity is supported */ conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, addr); if (!conn) { diff --git a/subsys/bluetooth/host/hci_core.c b/subsys/bluetooth/host/hci_core.c index 6a08e39274b..d4a153523a8 100644 --- a/subsys/bluetooth/host/hci_core.c +++ b/subsys/bluetooth/host/hci_core.c @@ -609,6 +609,78 @@ static int le_set_private_addr(u8_t id) } #endif +bool bt_le_scan_random_addr_check(void) +{ + /* 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)) { + return true; + } + + /* When privacy is enabled the random address will not be set + * immediately before starting the role, because the RPA might still be + * valid and only updated on RPA timeout. + */ + if (IS_ENABLED(CONFIG_BT_PRIVACY)) { + /* 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) { + return false; + } + } + + /* If privacy is not enabled then the random address will be attempted + * to be set before enabling the role. If another role is already using + * the random address then this command will fail, and should return + * the error code to the application. + */ + return true; +} + +static bool bt_le_adv_random_addr_check(const struct bt_le_adv_param *param) +{ + /* If scanner roles are not enabled or not active there is no issue. + * Passive scanner does not have an active address, unless it is a + * passive scanner that will start the initiator. + */ + if (IS_ENABLED(CONFIG_BT_OBSERVER) || + !(atomic_test_bit(bt_dev.flags, BT_DEV_INITIATING) || + (atomic_test_bit(bt_dev.flags, BT_DEV_SCANNING) && + (!atomic_test_bit(bt_dev.flags, BT_DEV_EXPLICIT_SCAN) || + atomic_test_bit(bt_dev.flags, BT_DEV_ACTIVE_SCAN))))) { + return true; + } + + /* When privacy is enabled the random address will not be set + * immediately before starting the role, because the RPA might still be + * valid and only updated on RPA timeout. + */ + if (IS_ENABLED(CONFIG_BT_PRIVACY)) { + /* Cannot start an advertiser with random static identity or + * using an RPA generated for a different identity than scanner + * roles. + */ + if (((param->options & BT_LE_ADV_OPT_USE_IDENTITY) && + bt_dev.id_addr[param->id].type == BT_ADDR_LE_RANDOM) || + param->id != BT_ID_DEFAULT) { + return false; + } + } + + /* If privacy is not enabled then the random address will be attempted + * to be set before enabling the role. If another role is already using + * the random address then this command will fail, and should return + * the error code to the application. + */ + return true; +} + + #if defined(CONFIG_BT_OBSERVER) static int set_le_scan_enable(u8_t enable) { @@ -5803,6 +5875,10 @@ int bt_le_adv_start_internal(const struct bt_le_adv_param *param, 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); @@ -5967,6 +6043,9 @@ int bt_le_adv_start_internal(const struct bt_le_adv_param *param, 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; } @@ -6100,6 +6179,9 @@ int bt_le_scan_start(const struct bt_le_scan_param *param, bt_le_scan_cb_t cb) return -EINVAL; } + 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; diff --git a/subsys/bluetooth/host/hci_core.h b/subsys/bluetooth/host/hci_core.h index 56b76f1b688..5a27b9f17f6 100644 --- a/subsys/bluetooth/host/hci_core.h +++ b/subsys/bluetooth/host/hci_core.h @@ -36,6 +36,7 @@ enum { BT_DEV_ADVERTISING, BT_DEV_ADVERTISING_NAME, BT_DEV_ADVERTISING_CONNECTABLE, + BT_DEV_ADVERTISING_IDENTITY, BT_DEV_KEEP_ADVERTISING, BT_DEV_SCANNING, BT_DEV_EXPLICIT_SCAN, @@ -210,3 +211,4 @@ int bt_le_adv_start_internal(const struct bt_le_adv_param *param, 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);