| /* |
| * Copyright (c) 2017-2021 Nordic Semiconductor ASA |
| * Copyright (c) 2015-2016 Intel Corporation |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| |
| #include <stdbool.h> |
| |
| #include <zephyr/settings/settings.h> |
| #include <zephyr/sys/byteorder.h> |
| #include <zephyr/sys/check.h> |
| |
| #include <zephyr/bluetooth/addr.h> |
| #include <zephyr/bluetooth/bluetooth.h> |
| #include <zephyr/bluetooth/hci_vs.h> |
| #include <zephyr/bluetooth/buf.h> |
| #include <zephyr/drivers/bluetooth/hci_driver.h> |
| #include <zephyr/sys/__assert.h> |
| |
| #include "hci_core.h" |
| #include "id.h" |
| #include "scan.h" |
| #include "adv.h" |
| #include "smp.h" |
| #include "conn_internal.h" |
| #include "keys.h" |
| #include "common/rpa.h" |
| |
| #include "settings.h" |
| |
| #include <zephyr/bluetooth/hci.h> |
| |
| #include "common/bt_str.h" |
| |
| #define LOG_LEVEL CONFIG_BT_HCI_CORE_LOG_LEVEL |
| #include <zephyr/logging/log.h> |
| LOG_MODULE_REGISTER(bt_id); |
| |
| struct bt_adv_id_check_data { |
| uint8_t id; |
| bool adv_enabled; |
| }; |
| |
| #if defined(CONFIG_BT_OBSERVER) || defined(CONFIG_BT_BROADCASTER) |
| const bt_addr_le_t *bt_lookup_id_addr(uint8_t id, const bt_addr_le_t *addr) |
| { |
| CHECKIF(id >= CONFIG_BT_ID_MAX || addr == NULL) { |
| return NULL; |
| } |
| |
| if (IS_ENABLED(CONFIG_BT_SMP)) { |
| struct bt_keys *keys; |
| |
| keys = bt_keys_find_irk(id, addr); |
| if (keys) { |
| LOG_DBG("Identity %s matched RPA %s", bt_addr_le_str(&keys->addr), |
| bt_addr_le_str(addr)); |
| return &keys->addr; |
| } |
| } |
| |
| return addr; |
| } |
| #endif /* CONFIG_BT_OBSERVER || CONFIG_BT_CONN */ |
| |
| static void adv_id_check_func(struct bt_le_ext_adv *adv, void *data) |
| { |
| struct bt_adv_id_check_data *check_data = data; |
| |
| if (IS_ENABLED(CONFIG_BT_EXT_ADV)) { |
| /* Only check if the ID is in use, as the advertiser can be |
| * started and stopped without reconfiguring parameters. |
| */ |
| if (check_data->id == adv->id) { |
| check_data->adv_enabled = true; |
| } |
| } else { |
| if (check_data->id == adv->id && |
| atomic_test_bit(adv->flags, BT_ADV_ENABLED)) { |
| check_data->adv_enabled = true; |
| } |
| } |
| } |
| |
| static void adv_is_private_enabled(struct bt_le_ext_adv *adv, void *data) |
| { |
| bool *adv_enabled = data; |
| |
| if (atomic_test_bit(adv->flags, BT_ADV_ENABLED) && |
| !atomic_test_bit(adv->flags, BT_ADV_USE_IDENTITY)) { |
| *adv_enabled = true; |
| } |
| } |
| |
| #if defined(CONFIG_BT_SMP) |
| static void adv_is_limited_enabled(struct bt_le_ext_adv *adv, void *data) |
| { |
| bool *adv_enabled = data; |
| |
| if (atomic_test_bit(adv->flags, BT_ADV_ENABLED) && |
| atomic_test_bit(adv->flags, BT_ADV_LIMITED)) { |
| *adv_enabled = true; |
| } |
| } |
| |
| static void adv_pause_enabled(struct bt_le_ext_adv *adv, void *data) |
| { |
| if (atomic_test_bit(adv->flags, BT_ADV_ENABLED)) { |
| atomic_set_bit(adv->flags, BT_ADV_PAUSED); |
| bt_le_adv_set_enable(adv, false); |
| } |
| } |
| |
| static void adv_unpause_enabled(struct bt_le_ext_adv *adv, void *data) |
| { |
| if (atomic_test_and_clear_bit(adv->flags, BT_ADV_PAUSED)) { |
| bt_le_adv_set_enable(adv, true); |
| } |
| } |
| #endif /* defined(CONFIG_BT_SMP) */ |
| |
| static int set_random_address(const bt_addr_t *addr) |
| { |
| struct net_buf *buf; |
| int err; |
| |
| LOG_DBG("%s", bt_addr_str(addr)); |
| |
| /* Do nothing if we already have the right address */ |
| if (bt_addr_eq(addr, &bt_dev.random_addr.a)) { |
| return 0; |
| } |
| |
| buf = bt_hci_cmd_create(BT_HCI_OP_LE_SET_RANDOM_ADDRESS, sizeof(*addr)); |
| if (!buf) { |
| return -ENOBUFS; |
| } |
| |
| net_buf_add_mem(buf, addr, sizeof(*addr)); |
| |
| err = bt_hci_cmd_send_sync(BT_HCI_OP_LE_SET_RANDOM_ADDRESS, buf, NULL); |
| if (err) { |
| return err; |
| } |
| |
| bt_addr_copy(&bt_dev.random_addr.a, addr); |
| bt_dev.random_addr.type = BT_ADDR_LE_RANDOM; |
| return 0; |
| } |
| |
| int bt_id_set_adv_random_addr(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; |
| |
| CHECKIF(adv == NULL || addr == NULL) { |
| return -EINVAL; |
| } |
| |
| if (!(IS_ENABLED(CONFIG_BT_EXT_ADV) && |
| BT_DEV_FEAT_LE_EXT_ADV(bt_dev.le.features))) { |
| return set_random_address(addr); |
| } |
| |
| LOG_DBG("%s", bt_addr_str(addr)); |
| |
| if (!atomic_test_bit(adv->flags, BT_ADV_PARAMS_SET)) { |
| bt_addr_copy(&adv->random_addr.a, addr); |
| adv->random_addr.type = BT_ADDR_LE_RANDOM; |
| atomic_set_bit(adv->flags, BT_ADV_RANDOM_ADDR_PENDING); |
| return 0; |
| } |
| |
| 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; |
| } |
| |
| if (&adv->random_addr.a != addr) { |
| bt_addr_copy(&adv->random_addr.a, addr); |
| } |
| adv->random_addr.type = BT_ADDR_LE_RANDOM; |
| return 0; |
| } |
| |
| /* If rpa sharing is enabled, then rpa expired cb of adv-sets belonging |
| * to same id is verified to return true. If not, adv-sets will continue |
| * with old rpa through out the rpa rotations. |
| */ |
| static void adv_rpa_expired(struct bt_le_ext_adv *adv, void *data) |
| { |
| bool rpa_invalid = true; |
| #if defined(CONFIG_BT_EXT_ADV) && defined(CONFIG_BT_PRIVACY) |
| /* Notify the user about the RPA timeout and set the RPA validity. */ |
| if (atomic_test_bit(adv->flags, BT_ADV_RPA_VALID) && |
| adv->cb && adv->cb->rpa_expired) { |
| rpa_invalid = adv->cb->rpa_expired(adv); |
| } |
| #endif |
| |
| if (IS_ENABLED(CONFIG_BT_RPA_SHARING)) { |
| |
| if (adv->id >= bt_dev.id_count) { |
| return; |
| } |
| bool *rpa_invalid_set_ptr = data; |
| |
| if (!rpa_invalid) { |
| rpa_invalid_set_ptr[adv->id] = false; |
| } |
| } else { |
| if (rpa_invalid) { |
| atomic_clear_bit(adv->flags, BT_ADV_RPA_VALID); |
| } |
| } |
| } |
| |
| static void adv_rpa_invalidate(struct bt_le_ext_adv *adv, void *data) |
| { |
| /* RPA of Advertisers limited by timeot or number of packets only expire |
| * when they are stopped. |
| */ |
| if (!atomic_test_bit(adv->flags, BT_ADV_LIMITED) && |
| !atomic_test_bit(adv->flags, BT_ADV_USE_IDENTITY)) { |
| adv_rpa_expired(adv, data); |
| } |
| } |
| |
| #if defined(CONFIG_BT_RPA_SHARING) |
| static void adv_rpa_clear_data(struct bt_le_ext_adv *adv, void *data) |
| { |
| if (adv->id >= bt_dev.id_count) { |
| return; |
| } |
| bool *rpa_invalid_set_ptr = data; |
| |
| if (rpa_invalid_set_ptr[adv->id]) { |
| atomic_clear_bit(adv->flags, BT_ADV_RPA_VALID); |
| bt_addr_copy(&bt_dev.rpa[adv->id], BT_ADDR_NONE); |
| } else { |
| LOG_WRN("Adv sets rpa expired cb with id %d returns false\n", adv->id); |
| } |
| } |
| #endif |
| |
| static void le_rpa_invalidate(void) |
| { |
| /* 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 (IS_ENABLED(CONFIG_BT_BROADCASTER)) { |
| |
| if (bt_dev.id_count == 0) { |
| return; |
| } |
| bool rpa_expired_data[bt_dev.id_count]; |
| |
| bt_le_ext_adv_foreach(adv_rpa_invalidate, &rpa_expired_data); |
| #if defined(CONFIG_BT_RPA_SHARING) |
| /* rpa_expired data collected. now clear data based on data collected. */ |
| bt_le_ext_adv_foreach(adv_rpa_clear_data, &rpa_expired_data); |
| #endif |
| } |
| } |
| |
| #if defined(CONFIG_BT_PRIVACY) |
| |
| #if defined(CONFIG_BT_RPA_TIMEOUT_DYNAMIC) |
| static void le_rpa_timeout_update(void) |
| { |
| int err = 0; |
| |
| if (atomic_test_and_clear_bit(bt_dev.flags, BT_DEV_RPA_TIMEOUT_CHANGED)) { |
| struct net_buf *buf; |
| struct bt_hci_cp_le_set_rpa_timeout *cp; |
| |
| buf = bt_hci_cmd_create(BT_HCI_OP_LE_SET_RPA_TIMEOUT, |
| sizeof(*cp)); |
| if (!buf) { |
| LOG_ERR("Failed to create HCI RPA timeout command"); |
| err = -ENOBUFS; |
| goto submit; |
| } |
| |
| cp = net_buf_add(buf, sizeof(*cp)); |
| cp->rpa_timeout = sys_cpu_to_le16(bt_dev.rpa_timeout); |
| err = bt_hci_cmd_send_sync(BT_HCI_OP_LE_SET_RPA_TIMEOUT, buf, NULL); |
| if (err) { |
| LOG_ERR("Failed to send HCI RPA timeout command"); |
| goto submit; |
| } |
| } |
| |
| submit: |
| if (err) { |
| atomic_set_bit(bt_dev.flags, BT_DEV_RPA_TIMEOUT_CHANGED); |
| } |
| } |
| #endif |
| |
| static void le_rpa_timeout_submit(void) |
| { |
| #if defined(CONFIG_BT_RPA_TIMEOUT_DYNAMIC) |
| le_rpa_timeout_update(); |
| #endif |
| |
| (void)k_work_schedule(&bt_dev.rpa_update, K_SECONDS(bt_dev.rpa_timeout)); |
| } |
| |
| /* this function sets new RPA only if current one is no longer valid */ |
| int bt_id_set_private_addr(uint8_t id) |
| { |
| bt_addr_t rpa; |
| int err; |
| |
| CHECKIF(id >= CONFIG_BT_ID_MAX) { |
| return -EINVAL; |
| } |
| |
| /* check if RPA is valid */ |
| if (atomic_test_bit(bt_dev.flags, BT_DEV_RPA_VALID)) { |
| return 0; |
| } |
| |
| err = bt_rpa_create(bt_dev.irk[id], &rpa); |
| if (!err) { |
| err = set_random_address(&rpa); |
| if (!err) { |
| atomic_set_bit(bt_dev.flags, BT_DEV_RPA_VALID); |
| } |
| } |
| |
| le_rpa_timeout_submit(); |
| |
| if (err) { |
| return err; |
| } |
| |
| if (IS_ENABLED(CONFIG_BT_LOG_SNIFFER_INFO)) { |
| LOG_INF("RPA: %s", bt_addr_str(&rpa)); |
| } |
| |
| return 0; |
| } |
| |
| #if defined(CONFIG_BT_RPA_SHARING) |
| static int adv_rpa_get(struct bt_le_ext_adv *adv, bt_addr_t *rpa) |
| { |
| int err; |
| |
| if (bt_addr_eq(&bt_dev.rpa[adv->id], BT_ADDR_NONE)) { |
| err = bt_rpa_create(bt_dev.irk[adv->id], &bt_dev.rpa[adv->id]); |
| if (err) { |
| return err; |
| } |
| } |
| |
| bt_addr_copy(rpa, &bt_dev.rpa[adv->id]); |
| |
| return 0; |
| } |
| #else |
| static int adv_rpa_get(struct bt_le_ext_adv *adv, bt_addr_t *rpa) |
| { |
| int err; |
| |
| err = bt_rpa_create(bt_dev.irk[adv->id], rpa); |
| if (err) { |
| return err; |
| } |
| |
| return 0; |
| } |
| #endif /* defined(CONFIG_BT_RPA_SHARING) */ |
| |
| int bt_id_set_adv_private_addr(struct bt_le_ext_adv *adv) |
| { |
| bt_addr_t rpa; |
| int err; |
| |
| CHECKIF(adv == NULL) { |
| return -EINVAL; |
| } |
| |
| if (IS_ENABLED(CONFIG_BT_PRIVACY) && |
| (adv->options & BT_LE_ADV_OPT_USE_NRPA)) { |
| /* The host doesn't support setting NRPAs when BT_PRIVACY=y. |
| * In that case you probably want to use an RPA anyway. |
| */ |
| LOG_ERR("NRPA not supported when BT_PRIVACY=y"); |
| |
| return -ENOSYS; |
| } |
| |
| if (!(IS_ENABLED(CONFIG_BT_EXT_ADV) && |
| BT_DEV_FEAT_LE_EXT_ADV(bt_dev.le.features))) { |
| return bt_id_set_private_addr(adv->id); |
| } |
| |
| /* check if RPA is valid */ |
| if (atomic_test_bit(adv->flags, BT_ADV_RPA_VALID)) { |
| /* Schedule the RPA timer if it is not running. |
| * The RPA may be valid without the timer running. |
| */ |
| if (!atomic_test_bit(adv->flags, BT_ADV_LIMITED)) { |
| le_rpa_timeout_submit(); |
| } |
| |
| return 0; |
| } |
| |
| if (adv == bt_le_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 = bt_id_set_private_addr(BT_ID_DEFAULT); |
| if (err) { |
| return err; |
| } |
| |
| err = bt_id_set_adv_random_addr(adv, &bt_dev.random_addr.a); |
| if (!err) { |
| atomic_set_bit(adv->flags, BT_ADV_RPA_VALID); |
| } |
| |
| return 0; |
| } |
| |
| err = adv_rpa_get(adv, &rpa); |
| if (!err) { |
| err = bt_id_set_adv_random_addr(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(); |
| } |
| |
| if (err) { |
| return err; |
| } |
| |
| if (IS_ENABLED(CONFIG_BT_LOG_SNIFFER_INFO)) { |
| LOG_INF("RPA: %s", bt_addr_str(&rpa)); |
| } |
| |
| return 0; |
| } |
| #else |
| int bt_id_set_private_addr(uint8_t id) |
| { |
| bt_addr_t nrpa; |
| int err; |
| |
| CHECKIF(id >= CONFIG_BT_ID_MAX) { |
| return -EINVAL; |
| } |
| |
| err = bt_rand(nrpa.val, sizeof(nrpa.val)); |
| if (err) { |
| return err; |
| } |
| |
| BT_ADDR_SET_NRPA(&nrpa); |
| |
| err = set_random_address(&nrpa); |
| if (err) { |
| return err; |
| } |
| |
| if (IS_ENABLED(CONFIG_BT_LOG_SNIFFER_INFO)) { |
| LOG_INF("NRPA: %s", bt_addr_str(&nrpa)); |
| } |
| |
| return 0; |
| } |
| |
| int bt_id_set_adv_private_addr(struct bt_le_ext_adv *adv) |
| { |
| bt_addr_t nrpa; |
| int err; |
| |
| CHECKIF(adv == NULL) { |
| return -EINVAL; |
| } |
| |
| err = bt_rand(nrpa.val, sizeof(nrpa.val)); |
| if (err) { |
| return err; |
| } |
| |
| BT_ADDR_SET_NRPA(&nrpa); |
| |
| err = bt_id_set_adv_random_addr(adv, &nrpa); |
| if (err) { |
| return err; |
| } |
| |
| if (IS_ENABLED(CONFIG_BT_LOG_SNIFFER_INFO)) { |
| LOG_INF("NRPA: %s", bt_addr_str(&nrpa)); |
| } |
| |
| return 0; |
| } |
| #endif /* defined(CONFIG_BT_PRIVACY) */ |
| |
| static void adv_pause_rpa(struct bt_le_ext_adv *adv, void *data) |
| { |
| bool *adv_enabled = data; |
| |
| /* Disable advertising sets to prepare them for RPA update. */ |
| if (atomic_test_bit(adv->flags, BT_ADV_ENABLED) && |
| !atomic_test_bit(adv->flags, BT_ADV_LIMITED) && |
| !atomic_test_bit(adv->flags, BT_ADV_USE_IDENTITY)) { |
| int err; |
| |
| err = bt_le_adv_set_enable_ext(adv, false, NULL); |
| if (err) { |
| LOG_ERR("Failed to disable advertising (err %d)", err); |
| } |
| |
| atomic_set_bit(adv->flags, BT_ADV_RPA_UPDATE); |
| *adv_enabled = true; |
| } |
| } |
| |
| static bool le_adv_rpa_timeout(void) |
| { |
| bool adv_enabled = false; |
| |
| if (IS_ENABLED(CONFIG_BT_BROADCASTER)) { |
| if (IS_ENABLED(CONFIG_BT_EXT_ADV) && |
| BT_DEV_FEAT_LE_EXT_ADV(bt_dev.le.features)) { |
| /* Pause all advertising sets using RPAs */ |
| bt_le_ext_adv_foreach(adv_pause_rpa, &adv_enabled); |
| } else { |
| /* Check if advertising set is enabled */ |
| bt_le_ext_adv_foreach(adv_is_private_enabled, &adv_enabled); |
| } |
| } |
| |
| return adv_enabled; |
| } |
| |
| static void adv_enable_rpa(struct bt_le_ext_adv *adv, void *data) |
| { |
| if (atomic_test_and_clear_bit(adv->flags, BT_ADV_RPA_UPDATE)) { |
| int err; |
| |
| err = bt_id_set_adv_private_addr(adv); |
| if (err) { |
| LOG_WRN("Failed to update advertiser RPA address (%d)", err); |
| } |
| |
| err = bt_le_adv_set_enable_ext(adv, true, NULL); |
| if (err) { |
| LOG_ERR("Failed to enable advertising (err %d)", err); |
| } |
| } |
| } |
| |
| static void le_update_private_addr(void) |
| { |
| struct bt_le_ext_adv *adv = NULL; |
| bool adv_enabled = false; |
| uint8_t id = BT_ID_DEFAULT; |
| int err; |
| |
| #if defined(CONFIG_BT_OBSERVER) |
| bool scan_enabled = false; |
| |
| if (atomic_test_bit(bt_dev.flags, BT_DEV_SCANNING) && |
| !(IS_ENABLED(CONFIG_BT_EXT_ADV) && |
| atomic_test_bit(bt_dev.flags, BT_DEV_SCAN_LIMITED))) { |
| bt_le_scan_set_enable(BT_HCI_LE_SCAN_DISABLE); |
| scan_enabled = true; |
| } |
| #endif |
| if (IS_ENABLED(CONFIG_BT_CENTRAL) && |
| IS_ENABLED(CONFIG_BT_FILTER_ACCEPT_LIST) && |
| atomic_test_bit(bt_dev.flags, BT_DEV_INITIATING)) { |
| /* Canceled initiating procedure will be restarted by |
| * connection complete event. |
| */ |
| bt_le_create_conn_cancel(); |
| } |
| |
| if (IS_ENABLED(CONFIG_BT_BROADCASTER) && |
| !(IS_ENABLED(CONFIG_BT_EXT_ADV) && |
| BT_DEV_FEAT_LE_EXT_ADV(bt_dev.le.features))) { |
| adv = bt_le_adv_lookup_legacy(); |
| |
| if (adv && |
| atomic_test_bit(adv->flags, BT_ADV_ENABLED) && |
| !atomic_test_bit(adv->flags, BT_ADV_USE_IDENTITY)) { |
| adv_enabled = true; |
| id = adv->id; |
| bt_le_adv_set_enable_legacy(adv, false); |
| } |
| } |
| |
| /* 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 = bt_id_set_private_addr(id); |
| if (err) { |
| LOG_WRN("Failed to update RPA address (%d)", err); |
| return; |
| } |
| |
| if (IS_ENABLED(CONFIG_BT_BROADCASTER) && |
| IS_ENABLED(CONFIG_BT_EXT_ADV) && |
| BT_DEV_FEAT_LE_EXT_ADV(bt_dev.le.features)) { |
| bt_le_ext_adv_foreach(adv_enable_rpa, NULL); |
| } |
| |
| if (IS_ENABLED(CONFIG_BT_BROADCASTER) && |
| adv && adv_enabled) { |
| bt_le_adv_set_enable_legacy(adv, true); |
| } |
| |
| #if defined(CONFIG_BT_OBSERVER) |
| if (scan_enabled) { |
| bt_le_scan_set_enable(BT_HCI_LE_SCAN_ENABLE); |
| } |
| #endif |
| } |
| |
| static void le_force_rpa_timeout(void) |
| { |
| #if defined(CONFIG_BT_PRIVACY) |
| struct k_work_sync sync; |
| |
| k_work_cancel_delayable_sync(&bt_dev.rpa_update, &sync); |
| #endif |
| (void)le_adv_rpa_timeout(); |
| le_rpa_invalidate(); |
| le_update_private_addr(); |
| } |
| |
| #if defined(CONFIG_BT_PRIVACY) |
| static void rpa_timeout(struct k_work *work) |
| { |
| bool adv_enabled; |
| |
| LOG_DBG(""); |
| |
| if (IS_ENABLED(CONFIG_BT_CENTRAL)) { |
| struct bt_conn *conn = |
| bt_conn_lookup_state_le(BT_ID_DEFAULT, NULL, |
| BT_CONN_CONNECTING_SCAN); |
| |
| if (conn) { |
| bt_conn_unref(conn); |
| bt_le_create_conn_cancel(); |
| } |
| } |
| |
| adv_enabled = le_adv_rpa_timeout(); |
| le_rpa_invalidate(); |
| |
| /* IF no roles using the RPA is running we can stop the RPA timer */ |
| if (!(adv_enabled || |
| 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_ACTIVE_SCAN)))) { |
| return; |
| } |
| |
| le_update_private_addr(); |
| } |
| #endif /* CONFIG_BT_PRIVACY */ |
| |
| bool bt_id_scan_random_addr_check(void) |
| { |
| struct bt_le_ext_adv *adv; |
| |
| if (!IS_ENABLED(CONFIG_BT_BROADCASTER) || |
| (IS_ENABLED(CONFIG_BT_EXT_ADV) && |
| BT_DEV_FEAT_LE_EXT_ADV(bt_dev.le.features))) { |
| /* Advertiser is not enabled or advertiser and scanner are using |
| * a different random address. |
| */ |
| return true; |
| } |
| |
| adv = bt_le_adv_lookup_legacy(); |
| if (!adv) { |
| return true; |
| } |
| |
| /* If the advertiser is not active there is no issue */ |
| if (!atomic_test_bit(adv->flags, BT_ADV_ENABLED)) { |
| 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 scanner 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(adv->flags, BT_ADV_USE_IDENTITY) && |
| bt_dev.id_addr[adv->id].type == BT_ADDR_LE_RANDOM) || |
| 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; |
| } |
| |
| bool bt_id_adv_random_addr_check(const struct bt_le_adv_param *param) |
| { |
| CHECKIF(param == NULL) { |
| return false; |
| } |
| |
| if (!IS_ENABLED(CONFIG_BT_OBSERVER) || |
| (IS_ENABLED(CONFIG_BT_EXT_ADV) && |
| BT_DEV_FEAT_LE_EXT_ADV(bt_dev.le.features))) { |
| /* If scanner roles are not enabled or advertiser and scanner |
| * are using a different random address. |
| */ |
| return true; |
| } |
| |
| /* If scanner roles are not active there is no issue. */ |
| if (!(atomic_test_bit(bt_dev.flags, BT_DEV_INITIATING) || |
| atomic_test_bit(bt_dev.flags, BT_DEV_SCANNING))) { |
| 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; |
| } |
| } else if (IS_ENABLED(CONFIG_BT_SCAN_WITH_IDENTITY) && |
| atomic_test_bit(bt_dev.flags, BT_DEV_SCANNING) && |
| bt_dev.id_addr[BT_ID_DEFAULT].type == BT_ADDR_LE_RANDOM) { |
| /* Scanning with random static identity. Stop the advertiser |
| * from overwriting the passive scanner identity address. |
| * In this case the LE Set Random Address command does not |
| * protect us in the case of a passive scanner. |
| * Explicitly stop it here. |
| */ |
| |
| if (!(param->options & BT_LE_ADV_OPT_CONNECTABLE) && |
| (param->options & BT_LE_ADV_OPT_USE_IDENTITY)) { |
| /* Attempt to set non-connectable NRPA */ |
| return false; |
| } else if (bt_dev.id_addr[param->id].type == |
| BT_ADDR_LE_RANDOM && |
| param->id != BT_ID_DEFAULT) { |
| /* Attempt to set connectable, or non-connectable with |
| * identity different than scanner. |
| */ |
| 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; |
| } |
| |
| void bt_id_adv_limited_stopped(struct bt_le_ext_adv *adv) |
| { |
| adv_rpa_expired(adv, NULL); |
| } |
| |
| #if defined(CONFIG_BT_SMP) |
| static int le_set_privacy_mode(const bt_addr_le_t *addr, uint8_t mode) |
| { |
| struct bt_hci_cp_le_set_privacy_mode cp; |
| struct net_buf *buf; |
| int err; |
| |
| /* Check if set privacy mode command is supported */ |
| if (!BT_CMD_TEST(bt_dev.supported_commands, 39, 2)) { |
| LOG_WRN("Set privacy mode command is not supported"); |
| return 0; |
| } |
| |
| LOG_DBG("addr %s mode 0x%02x", bt_addr_le_str(addr), mode); |
| |
| bt_addr_le_copy(&cp.id_addr, addr); |
| cp.mode = mode; |
| |
| buf = bt_hci_cmd_create(BT_HCI_OP_LE_SET_PRIVACY_MODE, sizeof(cp)); |
| if (!buf) { |
| return -ENOBUFS; |
| } |
| |
| net_buf_add_mem(buf, &cp, sizeof(cp)); |
| |
| err = bt_hci_cmd_send_sync(BT_HCI_OP_LE_SET_PRIVACY_MODE, buf, NULL); |
| if (err) { |
| return err; |
| } |
| |
| return 0; |
| } |
| |
| static int addr_res_enable(uint8_t enable) |
| { |
| struct net_buf *buf; |
| |
| LOG_DBG("%s", enable ? "enabled" : "disabled"); |
| |
| buf = bt_hci_cmd_create(BT_HCI_OP_LE_SET_ADDR_RES_ENABLE, 1); |
| if (!buf) { |
| return -ENOBUFS; |
| } |
| |
| net_buf_add_u8(buf, enable); |
| |
| return bt_hci_cmd_send_sync(BT_HCI_OP_LE_SET_ADDR_RES_ENABLE, |
| buf, NULL); |
| } |
| |
| static int hci_id_add(uint8_t id, const bt_addr_le_t *addr, uint8_t peer_irk[16]) |
| { |
| struct bt_hci_cp_le_add_dev_to_rl *cp; |
| struct net_buf *buf; |
| |
| if (id >= CONFIG_BT_ID_MAX) { |
| return -EINVAL; |
| } |
| |
| LOG_DBG("addr %s", bt_addr_le_str(addr)); |
| |
| buf = bt_hci_cmd_create(BT_HCI_OP_LE_ADD_DEV_TO_RL, sizeof(*cp)); |
| if (!buf) { |
| return -ENOBUFS; |
| } |
| |
| cp = net_buf_add(buf, sizeof(*cp)); |
| bt_addr_le_copy(&cp->peer_id_addr, addr); |
| memcpy(cp->peer_irk, peer_irk, 16); |
| |
| #if defined(CONFIG_BT_PRIVACY) |
| (void)memcpy(cp->local_irk, &bt_dev.irk[id], 16); |
| #else |
| (void)memset(cp->local_irk, 0, 16); |
| #endif |
| |
| return bt_hci_cmd_send_sync(BT_HCI_OP_LE_ADD_DEV_TO_RL, buf, NULL); |
| } |
| |
| static void pending_id_update(struct bt_keys *keys, void *data) |
| { |
| if (keys->state & BT_KEYS_ID_PENDING_ADD) { |
| keys->state &= ~BT_KEYS_ID_PENDING_ADD; |
| bt_id_add(keys); |
| return; |
| } |
| |
| if (keys->state & BT_KEYS_ID_PENDING_DEL) { |
| keys->state &= ~BT_KEYS_ID_PENDING_DEL; |
| bt_id_del(keys); |
| return; |
| } |
| } |
| |
| static void bt_id_pending_keys_update_set(struct bt_keys *keys, uint8_t flag) |
| { |
| atomic_set_bit(bt_dev.flags, BT_DEV_ID_PENDING); |
| keys->state |= flag; |
| } |
| |
| void bt_id_pending_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_type(BT_KEYS_ALL, pending_id_update, NULL); |
| } else { |
| bt_keys_foreach_type(BT_KEYS_IRK, pending_id_update, NULL); |
| } |
| } |
| } |
| |
| struct bt_id_conflict { |
| struct bt_keys *candidate; |
| struct bt_keys *found; |
| }; |
| |
| /* The Controller Resolve List is constrained by 7.8.38 "LE Add Device To |
| * Resolving List command". The Host is designed with the assumption that all |
| * local bonds can be put in the resolve list if there is room. Therefore we |
| * must refuse bonds that conflict in the resolve list. Notably, this prevents |
| * multiple local identities to bond with the same remote identity. |
| */ |
| void find_rl_conflict(struct bt_keys *resident, void *user_data) |
| { |
| struct bt_id_conflict *conflict = user_data; |
| bool addr_conflict; |
| bool irk_conflict; |
| |
| __ASSERT_NO_MSG(conflict != NULL); |
| __ASSERT_NO_MSG(conflict->candidate != NULL); |
| __ASSERT_NO_MSG(resident != NULL); |
| /* Only uncommitted bonds can be in conflict with committed bonds. */ |
| __ASSERT_NO_MSG((conflict->candidate->state & BT_KEYS_ID_ADDED) == 0); |
| |
| if (conflict->found) { |
| return; |
| } |
| |
| /* Test against committed bonds only. */ |
| if ((resident->state & BT_KEYS_ID_ADDED) == 0) { |
| return; |
| } |
| |
| addr_conflict = bt_addr_le_eq(&conflict->candidate->addr, &resident->addr); |
| |
| /* All-zero IRK is "no IRK", and does not conflict with other Zero-IRKs. */ |
| irk_conflict = (!bt_irk_eq(&conflict->candidate->irk, &(struct bt_irk){}) && |
| bt_irk_eq(&conflict->candidate->irk, &resident->irk)); |
| |
| if (addr_conflict || irk_conflict) { |
| conflict->found = resident; |
| } |
| } |
| |
| struct bt_keys *bt_id_find_conflict(struct bt_keys *candidate) |
| { |
| struct bt_id_conflict conflict = { |
| .candidate = candidate, |
| }; |
| |
| bt_keys_foreach_type(BT_KEYS_IRK, find_rl_conflict, &conflict); |
| |
| return conflict.found; |
| } |
| |
| void bt_id_add(struct bt_keys *keys) |
| { |
| CHECKIF(keys == NULL) { |
| return; |
| } |
| |
| struct bt_conn *conn; |
| int err; |
| |
| LOG_DBG("addr %s", bt_addr_le_str(&keys->addr)); |
| |
| __ASSERT_NO_MSG(keys != NULL); |
| /* We assume (and could assert) !bt_id_find_conflict(keys) here. */ |
| |
| /* Nothing to be done if host-side resolving is used */ |
| if (!bt_dev.le.rl_size || bt_dev.le.rl_entries > bt_dev.le.rl_size) { |
| bt_dev.le.rl_entries++; |
| keys->state |= BT_KEYS_ID_ADDED; |
| return; |
| } |
| |
| conn = bt_conn_lookup_state_le(BT_ID_DEFAULT, NULL, BT_CONN_CONNECTING); |
| if (conn) { |
| bt_id_pending_keys_update_set(keys, BT_KEYS_ID_PENDING_ADD); |
| bt_conn_unref(conn); |
| return; |
| } |
| |
| if (IS_ENABLED(CONFIG_BT_BROADCASTER) && |
| IS_ENABLED(CONFIG_BT_EXT_ADV)) { |
| bool adv_enabled = false; |
| |
| bt_le_ext_adv_foreach(adv_is_limited_enabled, &adv_enabled); |
| if (adv_enabled) { |
| bt_id_pending_keys_update_set(keys, |
| BT_KEYS_ID_PENDING_ADD); |
| return; |
| } |
| } |
| |
| #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)) { |
| bt_id_pending_keys_update_set(keys, BT_KEYS_ID_PENDING_ADD); |
| } |
| #endif |
| |
| if (IS_ENABLED(CONFIG_BT_BROADCASTER)) { |
| bt_le_ext_adv_foreach(adv_pause_enabled, NULL); |
| } |
| |
| #if defined(CONFIG_BT_OBSERVER) |
| if (scan_enabled) { |
| bt_le_scan_set_enable(BT_HCI_LE_SCAN_DISABLE); |
| } |
| #endif /* CONFIG_BT_OBSERVER */ |
| |
| /* If there are any existing entries address resolution will be on */ |
| if (bt_dev.le.rl_entries) { |
| err = addr_res_enable(BT_HCI_ADDR_RES_DISABLE); |
| if (err) { |
| LOG_WRN("Failed to disable address resolution"); |
| goto done; |
| } |
| } |
| |
| if (bt_dev.le.rl_entries == bt_dev.le.rl_size) { |
| LOG_WRN("Resolving list size exceeded. Switching to host."); |
| |
| err = bt_hci_cmd_send_sync(BT_HCI_OP_LE_CLEAR_RL, NULL, NULL); |
| if (err) { |
| LOG_ERR("Failed to clear resolution list"); |
| goto done; |
| } |
| |
| bt_dev.le.rl_entries++; |
| keys->state |= BT_KEYS_ID_ADDED; |
| |
| goto done; |
| } |
| |
| err = hci_id_add(keys->id, &keys->addr, keys->irk.val); |
| if (err) { |
| LOG_ERR("Failed to add IRK to controller"); |
| goto done; |
| } |
| |
| bt_dev.le.rl_entries++; |
| keys->state |= BT_KEYS_ID_ADDED; |
| |
| /* |
| * According to Core Spec. 5.0 Vol 1, Part A 5.4.5 Privacy Feature |
| * |
| * By default, network privacy mode is used when private addresses are |
| * resolved and generated by the Controller, so advertising packets from |
| * peer devices that contain private addresses will only be accepted. |
| * By changing to the device privacy mode device is only concerned about |
| * its privacy and will accept advertising packets from peer devices |
| * that contain their identity address as well as ones that contain |
| * a private address, even if the peer device has distributed its IRK in |
| * the past. |
| */ |
| err = le_set_privacy_mode(&keys->addr, BT_HCI_LE_PRIVACY_MODE_DEVICE); |
| if (err) { |
| LOG_ERR("Failed to set privacy mode"); |
| goto done; |
| } |
| |
| done: |
| addr_res_enable(BT_HCI_ADDR_RES_ENABLE); |
| |
| #if defined(CONFIG_BT_OBSERVER) |
| if (scan_enabled) { |
| bt_le_scan_set_enable(BT_HCI_LE_SCAN_ENABLE); |
| } |
| #endif /* CONFIG_BT_OBSERVER */ |
| |
| if (IS_ENABLED(CONFIG_BT_BROADCASTER)) { |
| bt_le_ext_adv_foreach(adv_unpause_enabled, NULL); |
| } |
| } |
| |
| static void keys_add_id(struct bt_keys *keys, void *data) |
| { |
| if (keys->state & BT_KEYS_ID_ADDED) { |
| hci_id_add(keys->id, &keys->addr, keys->irk.val); |
| } |
| } |
| |
| static int hci_id_del(const bt_addr_le_t *addr) |
| { |
| struct bt_hci_cp_le_rem_dev_from_rl *cp; |
| struct net_buf *buf; |
| |
| LOG_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_conn *conn; |
| int err; |
| |
| CHECKIF(keys == NULL) { |
| return; |
| } |
| |
| LOG_DBG("addr %s", bt_addr_le_str(&keys->addr)); |
| |
| if (!bt_dev.le.rl_size || |
| bt_dev.le.rl_entries > bt_dev.le.rl_size + 1) { |
| __ASSERT_NO_MSG(bt_dev.le.rl_entries > 0); |
| if (bt_dev.le.rl_entries > 0) { |
| bt_dev.le.rl_entries--; |
| } |
| keys->state &= ~BT_KEYS_ID_ADDED; |
| return; |
| } |
| |
| conn = bt_conn_lookup_state_le(BT_ID_DEFAULT, NULL, BT_CONN_CONNECTING); |
| if (conn) { |
| bt_id_pending_keys_update_set(keys, BT_KEYS_ID_PENDING_DEL); |
| bt_conn_unref(conn); |
| return; |
| } |
| |
| if (IS_ENABLED(CONFIG_BT_BROADCASTER) && |
| IS_ENABLED(CONFIG_BT_EXT_ADV)) { |
| bool adv_enabled = false; |
| |
| bt_le_ext_adv_foreach(adv_is_limited_enabled, &adv_enabled); |
| if (adv_enabled) { |
| bt_id_pending_keys_update_set(keys, BT_KEYS_ID_PENDING_DEL); |
| return; |
| } |
| } |
| |
| #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)) { |
| bt_id_pending_keys_update_set(keys, BT_KEYS_ID_PENDING_DEL); |
| } |
| #endif /* CONFIG_BT_OBSERVER */ |
| |
| if (IS_ENABLED(CONFIG_BT_BROADCASTER)) { |
| bt_le_ext_adv_foreach(adv_pause_enabled, NULL); |
| } |
| |
| #if defined(CONFIG_BT_OBSERVER) |
| if (scan_enabled) { |
| bt_le_scan_set_enable(BT_HCI_LE_SCAN_DISABLE); |
| } |
| #endif /* CONFIG_BT_OBSERVER */ |
| |
| err = addr_res_enable(BT_HCI_ADDR_RES_DISABLE); |
| if (err) { |
| LOG_ERR("Disabling address resolution failed (err %d)", err); |
| goto done; |
| } |
| |
| /* We checked size + 1 earlier, so here we know we can fit again */ |
| if (bt_dev.le.rl_entries > bt_dev.le.rl_size) { |
| bt_dev.le.rl_entries--; |
| keys->state &= ~BT_KEYS_ID_ADDED; |
| if (IS_ENABLED(CONFIG_BT_CENTRAL) && |
| IS_ENABLED(CONFIG_BT_PRIVACY)) { |
| bt_keys_foreach_type(BT_KEYS_ALL, keys_add_id, NULL); |
| } else { |
| bt_keys_foreach_type(BT_KEYS_IRK, keys_add_id, NULL); |
| } |
| goto done; |
| } |
| |
| err = hci_id_del(&keys->addr); |
| if (err) { |
| LOG_ERR("Failed to remove IRK from controller"); |
| goto done; |
| } |
| |
| bt_dev.le.rl_entries--; |
| keys->state &= ~BT_KEYS_ID_ADDED; |
| |
| done: |
| /* Only re-enable if there are entries to do resolving with */ |
| if (bt_dev.le.rl_entries) { |
| addr_res_enable(BT_HCI_ADDR_RES_ENABLE); |
| } |
| |
| #if defined(CONFIG_BT_OBSERVER) |
| if (scan_enabled) { |
| bt_le_scan_set_enable(BT_HCI_LE_SCAN_ENABLE); |
| } |
| #endif /* CONFIG_BT_OBSERVER */ |
| |
| if (IS_ENABLED(CONFIG_BT_BROADCASTER)) { |
| bt_le_ext_adv_foreach(adv_unpause_enabled, NULL); |
| } |
| } |
| #endif /* defined(CONFIG_BT_SMP) */ |
| |
| void bt_id_get(bt_addr_le_t *addrs, size_t *count) |
| { |
| if (addrs) { |
| size_t to_copy = MIN(*count, bt_dev.id_count); |
| |
| memcpy(addrs, bt_dev.id_addr, to_copy * sizeof(bt_addr_le_t)); |
| *count = to_copy; |
| } else { |
| *count = bt_dev.id_count; |
| } |
| } |
| |
| static int id_find(const bt_addr_le_t *addr) |
| { |
| uint8_t id; |
| |
| for (id = 0U; id < bt_dev.id_count; id++) { |
| if (bt_addr_le_eq(addr, &bt_dev.id_addr[id])) { |
| return id; |
| } |
| } |
| |
| return -ENOENT; |
| } |
| |
| static int id_create(uint8_t id, bt_addr_le_t *addr, uint8_t *irk) |
| { |
| if (addr && !bt_addr_le_eq(addr, BT_ADDR_LE_ANY)) { |
| bt_addr_le_copy(&bt_dev.id_addr[id], addr); |
| } else { |
| bt_addr_le_t new_addr; |
| |
| do { |
| int err; |
| |
| err = bt_addr_le_create_static(&new_addr); |
| if (err) { |
| return err; |
| } |
| /* Make sure we didn't generate a duplicate */ |
| } while (id_find(&new_addr) >= 0); |
| |
| bt_addr_le_copy(&bt_dev.id_addr[id], &new_addr); |
| |
| if (addr) { |
| bt_addr_le_copy(addr, &bt_dev.id_addr[id]); |
| } |
| } |
| |
| #if defined(CONFIG_BT_PRIVACY) |
| { |
| uint8_t zero_irk[16] = { 0 }; |
| |
| if (irk && memcmp(irk, zero_irk, 16)) { |
| memcpy(&bt_dev.irk[id], irk, 16); |
| } else { |
| int err; |
| |
| err = bt_rand(&bt_dev.irk[id], 16); |
| if (err) { |
| return err; |
| } |
| |
| if (irk) { |
| memcpy(irk, &bt_dev.irk[id], 16); |
| } |
| } |
| |
| #if defined(CONFIG_BT_RPA_SHARING) |
| bt_addr_copy(&bt_dev.rpa[id], BT_ADDR_NONE); |
| #endif |
| } |
| #endif |
| /* Only store if stack was already initialized. Before initialization |
| * we don't know the flash content, so it's potentially harmful to |
| * try to write anything there. |
| */ |
| if (IS_ENABLED(CONFIG_BT_SETTINGS) && |
| atomic_test_bit(bt_dev.flags, BT_DEV_READY)) { |
| (void)bt_settings_store_id(); |
| (void)bt_settings_store_irk(); |
| } |
| |
| return 0; |
| } |
| |
| int bt_id_create(bt_addr_le_t *addr, uint8_t *irk) |
| { |
| int new_id, err; |
| |
| if (!IS_ENABLED(CONFIG_BT_PRIVACY) && irk) { |
| return -EINVAL; |
| } |
| |
| if (addr && !bt_addr_le_eq(addr, BT_ADDR_LE_ANY)) { |
| if (id_find(addr) >= 0) { |
| return -EALREADY; |
| } |
| |
| if (addr->type == BT_ADDR_LE_PUBLIC && IS_ENABLED(CONFIG_BT_HCI_SET_PUBLIC_ADDR)) { |
| /* set the single public address */ |
| if (bt_dev.id_count != 0) { |
| return -EALREADY; |
| } |
| bt_addr_le_copy(&bt_dev.id_addr[BT_ID_DEFAULT], addr); |
| bt_dev.id_count++; |
| return BT_ID_DEFAULT; |
| } else if (addr->type != BT_ADDR_LE_RANDOM || !BT_ADDR_IS_STATIC(&addr->a)) { |
| LOG_ERR("Only random static identity address supported"); |
| return -EINVAL; |
| } |
| } |
| |
| if (bt_dev.id_count == ARRAY_SIZE(bt_dev.id_addr)) { |
| return -ENOMEM; |
| } |
| |
| /* bt_rand is not available before Bluetooth enable has been called */ |
| if (!atomic_test_bit(bt_dev.flags, BT_DEV_ENABLE)) { |
| uint8_t zero_irk[16] = { 0 }; |
| |
| if (!(addr && !bt_addr_le_eq(addr, BT_ADDR_LE_ANY))) { |
| return -EINVAL; |
| } |
| |
| if (IS_ENABLED(CONFIG_BT_PRIVACY) && |
| !(irk && memcmp(irk, zero_irk, 16))) { |
| return -EINVAL; |
| } |
| } |
| |
| new_id = bt_dev.id_count++; |
| err = id_create(new_id, addr, irk); |
| if (err) { |
| bt_dev.id_count--; |
| return err; |
| } |
| |
| return new_id; |
| } |
| |
| int bt_id_reset(uint8_t id, bt_addr_le_t *addr, uint8_t *irk) |
| { |
| int err; |
| |
| if (addr && !bt_addr_le_eq(addr, BT_ADDR_LE_ANY)) { |
| if (addr->type != BT_ADDR_LE_RANDOM || |
| !BT_ADDR_IS_STATIC(&addr->a)) { |
| LOG_ERR("Only static random identity address supported"); |
| return -EINVAL; |
| } |
| |
| if (id_find(addr) >= 0) { |
| return -EALREADY; |
| } |
| } |
| |
| if (!IS_ENABLED(CONFIG_BT_PRIVACY) && irk) { |
| return -EINVAL; |
| } |
| |
| if (id == BT_ID_DEFAULT || id >= bt_dev.id_count) { |
| return -EINVAL; |
| } |
| |
| if (IS_ENABLED(CONFIG_BT_BROADCASTER)) { |
| struct bt_adv_id_check_data check_data = { |
| .id = id, |
| .adv_enabled = false, |
| }; |
| |
| bt_le_ext_adv_foreach(adv_id_check_func, &check_data); |
| if (check_data.adv_enabled) { |
| return -EBUSY; |
| } |
| } |
| |
| if (IS_ENABLED(CONFIG_BT_CONN) && |
| !bt_addr_le_eq(&bt_dev.id_addr[id], BT_ADDR_LE_ANY)) { |
| err = bt_unpair(id, NULL); |
| if (err) { |
| return err; |
| } |
| } |
| |
| err = id_create(id, addr, irk); |
| if (err) { |
| return err; |
| } |
| |
| return id; |
| } |
| |
| int bt_id_delete(uint8_t id) |
| { |
| if (id == BT_ID_DEFAULT || id >= bt_dev.id_count) { |
| return -EINVAL; |
| } |
| |
| if (bt_addr_le_eq(&bt_dev.id_addr[id], BT_ADDR_LE_ANY)) { |
| return -EALREADY; |
| } |
| |
| if (IS_ENABLED(CONFIG_BT_BROADCASTER)) { |
| struct bt_adv_id_check_data check_data = { |
| .id = id, |
| .adv_enabled = false, |
| }; |
| |
| bt_le_ext_adv_foreach(adv_id_check_func, &check_data); |
| if (check_data.adv_enabled) { |
| return -EBUSY; |
| } |
| } |
| |
| if (IS_ENABLED(CONFIG_BT_CONN)) { |
| int err; |
| |
| err = bt_unpair(id, NULL); |
| if (err) { |
| return err; |
| } |
| } |
| |
| #if defined(CONFIG_BT_PRIVACY) |
| (void)memset(bt_dev.irk[id], 0, 16); |
| #endif |
| bt_addr_le_copy(&bt_dev.id_addr[id], BT_ADDR_LE_ANY); |
| |
| if (id == bt_dev.id_count - 1) { |
| bt_dev.id_count--; |
| } |
| |
| if (IS_ENABLED(CONFIG_BT_SETTINGS) && |
| atomic_test_bit(bt_dev.flags, BT_DEV_READY)) { |
| (void)bt_settings_store_id(); |
| (void)bt_settings_store_irk(); |
| } |
| |
| return 0; |
| } |
| |
| #if defined(CONFIG_BT_PRIVACY) |
| static void bt_read_identity_root(uint8_t *ir) |
| { |
| /* Invalid IR */ |
| memset(ir, 0, 16); |
| |
| #if defined(CONFIG_BT_HCI_VS_EXT) |
| struct bt_hci_rp_vs_read_key_hierarchy_roots *rp; |
| struct net_buf *rsp; |
| int err; |
| |
| if (!BT_VS_CMD_READ_KEY_ROOTS(bt_dev.vs_commands)) { |
| return; |
| } |
| |
| err = bt_hci_cmd_send_sync(BT_HCI_OP_VS_READ_KEY_HIERARCHY_ROOTS, NULL, |
| &rsp); |
| if (err) { |
| LOG_WRN("Failed to read identity root"); |
| return; |
| } |
| |
| if (IS_ENABLED(CONFIG_BT_HCI_VS_EXT_DETECT) && |
| rsp->len != sizeof(struct bt_hci_rp_vs_read_key_hierarchy_roots)) { |
| LOG_WRN("Invalid Vendor HCI extensions"); |
| net_buf_unref(rsp); |
| return; |
| } |
| |
| rp = (void *)rsp->data; |
| memcpy(ir, rp->ir, 16); |
| |
| net_buf_unref(rsp); |
| #endif /* defined(CONFIG_BT_HCI_VS_EXT) */ |
| } |
| #endif /* defined(CONFIG_BT_PRIVACY) */ |
| |
| uint8_t bt_id_read_public_addr(bt_addr_le_t *addr) |
| { |
| struct bt_hci_rp_read_bd_addr *rp; |
| struct net_buf *rsp; |
| int err; |
| |
| CHECKIF(addr == NULL) { |
| LOG_WRN("Invalid input parameters"); |
| return 0U; |
| } |
| |
| /* Read Bluetooth Address */ |
| err = bt_hci_cmd_send_sync(BT_HCI_OP_READ_BD_ADDR, NULL, &rsp); |
| if (err) { |
| LOG_WRN("Failed to read public address"); |
| return 0U; |
| } |
| |
| rp = (void *)rsp->data; |
| |
| if (bt_addr_eq(&rp->bdaddr, BT_ADDR_ANY) || |
| bt_addr_eq(&rp->bdaddr, BT_ADDR_NONE)) { |
| LOG_DBG("Controller has no public address"); |
| net_buf_unref(rsp); |
| return 0U; |
| } |
| |
| bt_addr_copy(&addr->a, &rp->bdaddr); |
| addr->type = BT_ADDR_LE_PUBLIC; |
| |
| net_buf_unref(rsp); |
| return 1U; |
| } |
| |
| int bt_setup_public_id_addr(void) |
| { |
| bt_addr_le_t addr; |
| uint8_t *irk = NULL; |
| |
| bt_dev.id_count = bt_id_read_public_addr(&addr); |
| |
| if (!bt_dev.id_count) { |
| return 0; |
| } |
| |
| #if defined(CONFIG_BT_PRIVACY) |
| uint8_t ir_irk[16]; |
| uint8_t ir[16]; |
| |
| bt_read_identity_root(ir); |
| |
| if (!IS_ENABLED(CONFIG_BT_PRIVACY_RANDOMIZE_IR)) { |
| if (!bt_smp_irk_get(ir, ir_irk)) { |
| irk = ir_irk; |
| } |
| } |
| #endif /* defined(CONFIG_BT_PRIVACY) */ |
| |
| /* If true, `id_create` will randomize the IRK. */ |
| if (!irk && IS_ENABLED(CONFIG_BT_PRIVACY)) { |
| /* `id_create` will not store the id when called before BT_DEV_READY. |
| * But since part of the id will be randomized, it needs to be stored. |
| */ |
| if (IS_ENABLED(CONFIG_BT_SETTINGS)) { |
| atomic_set_bit(bt_dev.flags, BT_DEV_STORE_ID); |
| } |
| } |
| |
| return id_create(BT_ID_DEFAULT, &addr, irk); |
| } |
| |
| #if defined(CONFIG_BT_HCI_VS_EXT) |
| uint8_t bt_read_static_addr(struct bt_hci_vs_static_addr addrs[], uint8_t size) |
| { |
| struct bt_hci_rp_vs_read_static_addrs *rp; |
| struct net_buf *rsp; |
| int err, i; |
| uint8_t cnt; |
| |
| if (!BT_VS_CMD_READ_STATIC_ADDRS(bt_dev.vs_commands)) { |
| LOG_WRN("Read Static Addresses command not available"); |
| return 0; |
| } |
| |
| err = bt_hci_cmd_send_sync(BT_HCI_OP_VS_READ_STATIC_ADDRS, NULL, &rsp); |
| if (err) { |
| LOG_WRN("Failed to read static addresses"); |
| return 0; |
| } |
| |
| if (IS_ENABLED(CONFIG_BT_HCI_VS_EXT_DETECT) && |
| rsp->len < sizeof(struct bt_hci_rp_vs_read_static_addrs)) { |
| LOG_WRN("Invalid Vendor HCI extensions"); |
| net_buf_unref(rsp); |
| return 0; |
| } |
| |
| rp = (void *)rsp->data; |
| cnt = MIN(rp->num_addrs, size); |
| |
| if (IS_ENABLED(CONFIG_BT_HCI_VS_EXT_DETECT) && |
| rsp->len != (sizeof(struct bt_hci_rp_vs_read_static_addrs) + |
| rp->num_addrs * |
| sizeof(struct bt_hci_vs_static_addr))) { |
| LOG_WRN("Invalid Vendor HCI extensions"); |
| net_buf_unref(rsp); |
| return 0; |
| } |
| |
| for (i = 0; i < cnt; i++) { |
| memcpy(&addrs[i], &rp->a[i], sizeof(struct bt_hci_vs_static_addr)); |
| } |
| |
| net_buf_unref(rsp); |
| if (!cnt) { |
| LOG_WRN("No static addresses stored in controller"); |
| } |
| |
| return cnt; |
| } |
| #endif /* CONFIG_BT_HCI_VS_EXT */ |
| |
| int bt_setup_random_id_addr(void) |
| { |
| #if defined(CONFIG_BT_HCI_VS_EXT) || defined(CONFIG_BT_CTLR) |
| /* Only read the addresses if the user has not already configured one or |
| * more identities (!bt_dev.id_count). |
| */ |
| if (!bt_dev.id_count) { |
| struct bt_hci_vs_static_addr addrs[CONFIG_BT_ID_MAX]; |
| |
| bt_dev.id_count = bt_read_static_addr(addrs, CONFIG_BT_ID_MAX); |
| |
| if (bt_dev.id_count) { |
| for (uint8_t i = 0; i < bt_dev.id_count; i++) { |
| int err; |
| bt_addr_le_t addr; |
| uint8_t *irk = NULL; |
| #if defined(CONFIG_BT_PRIVACY) |
| uint8_t ir_irk[16]; |
| |
| if (!IS_ENABLED(CONFIG_BT_PRIVACY_RANDOMIZE_IR)) { |
| if (!bt_smp_irk_get(addrs[i].ir, ir_irk)) { |
| irk = ir_irk; |
| } |
| } |
| #endif /* CONFIG_BT_PRIVACY */ |
| |
| /* If true, `id_create` will randomize the IRK. */ |
| if (!irk && IS_ENABLED(CONFIG_BT_PRIVACY)) { |
| /* `id_create` will not store the id when called before |
| * BT_DEV_READY. But since part of the id will be |
| * randomized, it needs to be stored. |
| */ |
| if (IS_ENABLED(CONFIG_BT_SETTINGS)) { |
| atomic_set_bit(bt_dev.flags, BT_DEV_STORE_ID); |
| } |
| } |
| |
| bt_addr_copy(&addr.a, &addrs[i].bdaddr); |
| addr.type = BT_ADDR_LE_RANDOM; |
| |
| err = id_create(i, &addr, irk); |
| if (err) { |
| return err; |
| } |
| } |
| |
| return 0; |
| } |
| } |
| #endif /* defined(CONFIG_BT_HCI_VS_EXT) || defined(CONFIG_BT_CTLR) */ |
| |
| if (IS_ENABLED(CONFIG_BT_PRIVACY) && IS_ENABLED(CONFIG_BT_SETTINGS)) { |
| atomic_set_bit(bt_dev.flags, BT_DEV_STORE_ID); |
| } |
| |
| return bt_id_create(NULL, NULL); |
| } |
| |
| #if defined(CONFIG_BT_CENTRAL) |
| static inline bool rpa_timeout_valid_check(void) |
| { |
| #if defined(CONFIG_BT_PRIVACY) |
| uint32_t remaining_ms = k_ticks_to_ms_floor32( |
| k_work_delayable_remaining_get(&bt_dev.rpa_update)); |
| /* Check if create conn timeout will happen before RPA timeout. */ |
| return remaining_ms > (10 * bt_dev.create_param.timeout); |
| #else |
| return true; |
| #endif |
| } |
| |
| int bt_id_set_create_conn_own_addr(bool use_filter, uint8_t *own_addr_type) |
| { |
| int err; |
| |
| CHECKIF(own_addr_type == NULL) { |
| return -EINVAL; |
| } |
| |
| if (IS_ENABLED(CONFIG_BT_PRIVACY)) { |
| if (use_filter || rpa_timeout_valid_check()) { |
| err = bt_id_set_private_addr(BT_ID_DEFAULT); |
| if (err) { |
| return err; |
| } |
| } else { |
| /* Force new RPA timeout so that RPA timeout is not |
| * triggered while direct initiator is active. |
| */ |
| le_force_rpa_timeout(); |
| } |
| |
| 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) { |
| err = set_random_address(&addr->a); |
| if (err) { |
| return err; |
| } |
| } |
| |
| *own_addr_type = addr->type; |
| } |
| |
| return 0; |
| } |
| #endif /* defined(CONFIG_BT_CENTRAL) */ |
| |
| #if defined(CONFIG_BT_OBSERVER) |
| static bool is_adv_using_rand_addr(void) |
| { |
| struct bt_le_ext_adv *adv; |
| |
| if (!IS_ENABLED(CONFIG_BT_BROADCASTER) || |
| (IS_ENABLED(CONFIG_BT_EXT_ADV) && |
| BT_DEV_FEAT_LE_EXT_ADV(bt_dev.le.features))) { |
| /* When advertising is not enabled or is using extended |
| * advertising HCI commands then only the scanner uses the set |
| * random address command. |
| */ |
| return false; |
| } |
| |
| adv = bt_le_adv_lookup_legacy(); |
| |
| return adv && atomic_test_bit(adv->flags, BT_ADV_ENABLED); |
| } |
| |
| int bt_id_set_scan_own_addr(bool active_scan, uint8_t *own_addr_type) |
| { |
| int err; |
| |
| CHECKIF(own_addr_type == NULL) { |
| return -EINVAL; |
| } |
| |
| if (IS_ENABLED(CONFIG_BT_PRIVACY)) { |
| err = bt_id_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 { |
| *own_addr_type = bt_dev.id_addr[0].type; |
| |
| /* Use NRPA unless identity has been explicitly requested |
| * (through Kconfig). |
| * Use same RPA as legacy advertiser if advertising. |
| */ |
| if (!IS_ENABLED(CONFIG_BT_SCAN_WITH_IDENTITY) && |
| !is_adv_using_rand_addr()) { |
| err = bt_id_set_private_addr(BT_ID_DEFAULT); |
| if (err) { |
| if (active_scan || !is_adv_using_rand_addr()) { |
| return err; |
| } |
| |
| LOG_WRN("Ignoring failure to set address for passive scan (%d)", |
| err); |
| } |
| |
| *own_addr_type = BT_ADDR_LE_RANDOM; |
| } else if (IS_ENABLED(CONFIG_BT_SCAN_WITH_IDENTITY) && |
| *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 |
| * directed towards this identity. |
| */ |
| err = set_random_address(&bt_dev.id_addr[0].a); |
| if (err) { |
| return err; |
| } |
| } else { |
| LOG_DBG("Not changing the address"); |
| } |
| } |
| |
| return 0; |
| } |
| #endif /* defined(CONFIG_BT_OBSERVER) */ |
| |
| int bt_id_set_adv_own_addr(struct bt_le_ext_adv *adv, uint32_t options, |
| bool dir_adv, uint8_t *own_addr_type) |
| { |
| const bt_addr_le_t *id_addr; |
| int err = 0; |
| |
| CHECKIF(adv == NULL || own_addr_type == NULL) { |
| return -EINVAL; |
| } |
| |
| /* Set which local identity address we're advertising with */ |
| id_addr = &bt_dev.id_addr[adv->id]; |
| |
| /* Short-circuit to force NRPA usage */ |
| if (options & BT_LE_ADV_OPT_USE_NRPA) { |
| if (options & BT_LE_ADV_OPT_USE_IDENTITY) { |
| LOG_ERR("Can't set both IDENTITY & NRPA"); |
| |
| return -EINVAL; |
| } |
| |
| err = bt_id_set_adv_private_addr(adv); |
| if (err) { |
| return err; |
| } |
| *own_addr_type = BT_ADDR_LE_RANDOM; |
| |
| return 0; |
| } |
| |
| if (options & BT_LE_ADV_OPT_CONNECTABLE) { |
| if (dir_adv && (options & BT_LE_ADV_OPT_DIR_ADDR_RPA) && |
| !BT_FEAT_LE_PRIVACY(bt_dev.le.features)) { |
| return -ENOTSUP; |
| } |
| |
| if (IS_ENABLED(CONFIG_BT_PRIVACY) && |
| !(options & BT_LE_ADV_OPT_USE_IDENTITY)) { |
| err = bt_id_set_adv_private_addr(adv); |
| if (err) { |
| return err; |
| } |
| |
| if (dir_adv && (options & BT_LE_ADV_OPT_DIR_ADDR_RPA)) { |
| *own_addr_type = BT_HCI_OWN_ADDR_RPA_OR_RANDOM; |
| } else { |
| *own_addr_type = BT_ADDR_LE_RANDOM; |
| } |
| } else { |
| /* |
| * If Static Random address is used as Identity |
| * address we need to restore it before advertising |
| * is enabled. Otherwise NRPA used for active scan |
| * could be used for advertising. |
| */ |
| if (id_addr->type == BT_ADDR_LE_RANDOM) { |
| err = bt_id_set_adv_random_addr(adv, &id_addr->a); |
| if (err) { |
| return err; |
| } |
| } |
| |
| *own_addr_type = id_addr->type; |
| |
| if (dir_adv && (options & BT_LE_ADV_OPT_DIR_ADDR_RPA)) { |
| *own_addr_type |= BT_HCI_OWN_ADDR_RPA_MASK; |
| } |
| } |
| } else { |
| if (options & BT_LE_ADV_OPT_USE_IDENTITY) { |
| if (id_addr->type == BT_ADDR_LE_RANDOM) { |
| err = bt_id_set_adv_random_addr(adv, &id_addr->a); |
| } |
| |
| *own_addr_type = id_addr->type; |
| } else if (!(IS_ENABLED(CONFIG_BT_EXT_ADV) && |
| BT_DEV_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; |
| |
| /* If active scan with NRPA is ongoing refresh NRPA */ |
| if (!IS_ENABLED(CONFIG_BT_PRIVACY) && |
| !IS_ENABLED(CONFIG_BT_SCAN_WITH_IDENTITY) && |
| atomic_test_bit(bt_dev.flags, BT_DEV_SCANNING)) { |
| scan_enabled = true; |
| bt_le_scan_set_enable(BT_HCI_LE_SCAN_DISABLE); |
| } |
| #endif /* defined(CONFIG_BT_OBSERVER) */ |
| err = bt_id_set_adv_private_addr(adv); |
| *own_addr_type = BT_ADDR_LE_RANDOM; |
| |
| #if defined(CONFIG_BT_OBSERVER) |
| if (scan_enabled) { |
| bt_le_scan_set_enable(BT_HCI_LE_SCAN_ENABLE); |
| } |
| #endif /* defined(CONFIG_BT_OBSERVER) */ |
| } else { |
| err = bt_id_set_adv_private_addr(adv); |
| *own_addr_type = BT_ADDR_LE_RANDOM; |
| } |
| |
| if (err) { |
| return err; |
| } |
| } |
| |
| return 0; |
| } |
| |
| #if defined(CONFIG_BT_CLASSIC) |
| int bt_br_oob_get_local(struct bt_br_oob *oob) |
| { |
| CHECKIF(oob == NULL) { |
| return -EINVAL; |
| } |
| |
| bt_addr_copy(&oob->addr, &bt_dev.id_addr[0].a); |
| |
| return 0; |
| } |
| #endif /* CONFIG_BT_CLASSIC */ |
| |
| int bt_le_oob_get_local(uint8_t id, struct bt_le_oob *oob) |
| { |
| struct bt_le_ext_adv *adv = NULL; |
| int err; |
| |
| CHECKIF(oob == NULL) { |
| return -EINVAL; |
| } |
| |
| if (!atomic_test_bit(bt_dev.flags, BT_DEV_READY)) { |
| return -EAGAIN; |
| } |
| |
| if (id >= CONFIG_BT_ID_MAX) { |
| return -EINVAL; |
| } |
| |
| if (IS_ENABLED(CONFIG_BT_BROADCASTER)) { |
| adv = bt_le_adv_lookup_legacy(); |
| } |
| |
| if (IS_ENABLED(CONFIG_BT_PRIVACY) && |
| !(adv && adv->id == id && |
| atomic_test_bit(adv->flags, BT_ADV_ENABLED) && |
| atomic_test_bit(adv->flags, BT_ADV_USE_IDENTITY) && |
| 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)) { |
| struct bt_conn *conn; |
| |
| conn = bt_conn_lookup_state_le(BT_ID_DEFAULT, NULL, |
| BT_CONN_CONNECTING_SCAN); |
| if (conn) { |
| /* Cannot set new RPA while creating |
| * connections. |
| */ |
| bt_conn_unref(conn); |
| return -EINVAL; |
| } |
| } |
| |
| if (adv && |
| atomic_test_bit(adv->flags, BT_ADV_ENABLED) && |
| atomic_test_bit(adv->flags, BT_ADV_USE_IDENTITY) && |
| (bt_dev.id_addr[id].type == BT_ADDR_LE_RANDOM)) { |
| /* Cannot set a new RPA address while advertising with |
| * random static identity address for a different |
| * identity. |
| */ |
| return -EINVAL; |
| } |
| |
| if (IS_ENABLED(CONFIG_BT_OBSERVER) && |
| CONFIG_BT_ID_MAX > 1 && |
| id != BT_ID_DEFAULT && |
| (atomic_test_bit(bt_dev.flags, BT_DEV_SCANNING) || |
| atomic_test_bit(bt_dev.flags, BT_DEV_INITIATING))) { |
| /* Cannot switch identity of scanner or initiator */ |
| return -EINVAL; |
| } |
| |
| le_force_rpa_timeout(); |
| |
| bt_addr_le_copy(&oob->addr, &bt_dev.random_addr); |
| } else { |
| 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 && err != -ENOTSUP) { |
| 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; |
| |
| CHECKIF(adv == NULL || oob == NULL) { |
| return -EINVAL; |
| } |
| |
| if (!atomic_test_bit(bt_dev.flags, BT_DEV_READY)) { |
| return -EAGAIN; |
| } |
| |
| if (IS_ENABLED(CONFIG_BT_PRIVACY) && |
| !atomic_test_bit(adv->flags, BT_ADV_USE_IDENTITY)) { |
| /* Don't refresh RPA addresses if the RPA is new. |
| * This allows back to back calls to this function or |
| * bt_le_oob_get_local to not invalidate the previously set |
| * RPAs. |
| */ |
| if (!atomic_test_bit(adv->flags, BT_ADV_LIMITED) && |
| !bt_id_rpa_is_new()) { |
| 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_CONNECTING_SCAN); |
| |
| if (conn) { |
| /* Cannot set new RPA while creating |
| * connections. |
| */ |
| bt_conn_unref(conn); |
| return -EINVAL; |
| } |
| } |
| |
| le_force_rpa_timeout(); |
| } |
| |
| 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)) { |
| err = bt_smp_le_oob_generate_sc_data(&oob->le_sc_data); |
| if (err && err != -ENOTSUP) { |
| return err; |
| } |
| } |
| |
| return 0; |
| } |
| #endif /* defined(CONFIG_BT_EXT_ADV) */ |
| |
| #if defined(CONFIG_BT_SMP) |
| #if !defined(CONFIG_BT_SMP_SC_PAIR_ONLY) |
| int bt_le_oob_set_legacy_tk(struct bt_conn *conn, const uint8_t *tk) |
| { |
| CHECKIF(conn == NULL || tk == NULL) { |
| return -EINVAL; |
| } |
| |
| return bt_smp_le_oob_set_tk(conn, tk); |
| } |
| #endif /* !defined(CONFIG_BT_SMP_SC_PAIR_ONLY) */ |
| |
| #if !defined(CONFIG_BT_SMP_OOB_LEGACY_PAIR_ONLY) |
| int bt_le_oob_set_sc_data(struct bt_conn *conn, |
| const struct bt_le_oob_sc_data *oobd_local, |
| const struct bt_le_oob_sc_data *oobd_remote) |
| { |
| CHECKIF(conn == NULL) { |
| return -EINVAL; |
| } |
| |
| if (!atomic_test_bit(bt_dev.flags, BT_DEV_READY)) { |
| return -EAGAIN; |
| } |
| |
| return bt_smp_le_oob_set_sc_data(conn, oobd_local, oobd_remote); |
| } |
| |
| int bt_le_oob_get_sc_data(struct bt_conn *conn, |
| const struct bt_le_oob_sc_data **oobd_local, |
| const struct bt_le_oob_sc_data **oobd_remote) |
| { |
| CHECKIF(conn == NULL) { |
| return -EINVAL; |
| } |
| |
| if (!atomic_test_bit(bt_dev.flags, BT_DEV_READY)) { |
| return -EAGAIN; |
| } |
| |
| return bt_smp_le_oob_get_sc_data(conn, oobd_local, oobd_remote); |
| } |
| #endif /* !defined(CONFIG_BT_SMP_OOB_LEGACY_PAIR_ONLY) */ |
| #endif /* defined(CONFIG_BT_SMP) */ |
| |
| int bt_id_init(void) |
| { |
| int err; |
| |
| #if defined(CONFIG_BT_PRIVACY) |
| k_work_init_delayable(&bt_dev.rpa_update, rpa_timeout); |
| #if defined(CONFIG_BT_RPA_SHARING) |
| for (uint8_t id = 0U; id < ARRAY_SIZE(bt_dev.rpa); id++) { |
| bt_addr_copy(&bt_dev.rpa[id], BT_ADDR_NONE); |
| } |
| #endif |
| #endif |
| |
| if (!IS_ENABLED(CONFIG_BT_SETTINGS) && !bt_dev.id_count) { |
| LOG_DBG("No user identity. Trying to set public."); |
| |
| err = bt_setup_public_id_addr(); |
| if (err) { |
| LOG_ERR("Unable to set identity address"); |
| return err; |
| } |
| } |
| |
| if (!IS_ENABLED(CONFIG_BT_SETTINGS) && !bt_dev.id_count) { |
| LOG_DBG("No public address. Trying to set static random."); |
| |
| err = bt_setup_random_id_addr(); |
| if (err) { |
| LOG_ERR("Unable to set identity address"); |
| return err; |
| } |
| |
| /* The passive scanner just sends a dummy address type in the |
| * command. If the first activity does this, and the dummy type |
| * is a random address, it needs a valid value, even though it's |
| * not actually used. |
| */ |
| err = set_random_address(&bt_dev.id_addr[0].a); |
| if (err) { |
| LOG_ERR("Unable to set random address"); |
| return err; |
| } |
| } |
| |
| return 0; |
| } |