From 467bf7c4725d7d85ee681275e7f755becdfc0b70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5vard=20Reierstad?= Date: Tue, 25 Nov 2025 07:53:18 +0100 Subject: [PATCH 1/4] Revert "[nrf noup] bluetooth: host: Add support for bonding with same peer" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 4994883cb4f5b53f64c5909798a5dfd6ee79e376. Signed-off-by: Håvard Reierstad --- include/zephyr/bluetooth/bluetooth.h | 10 -- subsys/bluetooth/host/Kconfig | 18 --- subsys/bluetooth/host/adv.c | 52 ------- subsys/bluetooth/host/adv.h | 1 - subsys/bluetooth/host/hci_core.h | 23 +-- subsys/bluetooth/host/id.c | 219 +++------------------------ subsys/bluetooth/host/id.h | 23 --- subsys/bluetooth/host/keys.c | 79 +--------- subsys/bluetooth/host/keys.h | 6 - subsys/bluetooth/host/smp.c | 18 +-- tests/bluetooth/host/id/mocks/adv.c | 1 - tests/bluetooth/host/id/mocks/adv.h | 4 +- tests/bluetooth/host/id/mocks/keys.c | 1 - tests/bluetooth/host/id/mocks/keys.h | 4 +- 14 files changed, 32 insertions(+), 427 deletions(-) diff --git a/include/zephyr/bluetooth/bluetooth.h b/include/zephyr/bluetooth/bluetooth.h index 0739733c9543..8e738d21970d 100644 --- a/include/zephyr/bluetooth/bluetooth.h +++ b/include/zephyr/bluetooth/bluetooth.h @@ -1295,10 +1295,6 @@ struct bt_le_per_adv_param { * This error code is only guaranteed when using Zephyr * controller, for other controllers code returned in * this case may be -EIO. - * @return -EPERM When @kconfig{CONFIG_BT_PRIVACY} and - * @kconfig{CONFIG_BT_ID_AUTO_SWAP_MATCHING_BONDS} are enabled and connectable - * advertising is requested, and the given local identity has a conflicting - * key with another local identity for which advertising is already started. */ int bt_le_adv_start(const struct bt_le_adv_param *param, const struct bt_data *ad, size_t ad_len, @@ -1426,12 +1422,6 @@ struct bt_le_ext_adv_start_param { * * @param adv Advertising set object. * @param param Advertise start parameters. - * - * @return Zero on success or (negative) error code otherwise. - * @return -EPERM When @kconfig{CONFIG_BT_PRIVACY} and - * @kconfig{CONFIG_BT_ID_AUTO_SWAP_MATCHING_BONDS} are enabled and connectable - * advertising is requested, and the given local identity has a conflicting - * key with another local identity for which advertising is already started. */ int bt_le_ext_adv_start(struct bt_le_ext_adv *adv, const struct bt_le_ext_adv_start_param *param); diff --git a/subsys/bluetooth/host/Kconfig b/subsys/bluetooth/host/Kconfig index 9eba33273066..8920d41d0e07 100644 --- a/subsys/bluetooth/host/Kconfig +++ b/subsys/bluetooth/host/Kconfig @@ -659,24 +659,6 @@ config BT_ID_UNPAIR_MATCHING_BONDS link-layer. The Host does not have control over this acknowledgment, and the order of distribution is fixed by the specification. -config BT_ID_AUTO_SWAP_MATCHING_BONDS - bool "Automatically swap conflicting entries in the Resolving List" - depends on !BT_ID_UNPAIR_MATCHING_BONDS - depends on BT_SMP && BT_PERIPHERAL && !BT_CENTRAL - help - If this option is enabled, the Host will not add a new bond with - the same peer address (or IRK) to the Resolving List if there is - already a bond with the same peer address (or IRK) on another local - identity. - - In case of Peripheral, the Host will swap the existing entry in the - Resolving List with the new one, so that the new bond will be used for - address resolution for the new local identity if the device starts - advertising with the new local identity. - - Important: this option is supported exclusively in the Peripheral - role. Excluding the Central role. - config BT_ID_ALLOW_UNAUTH_OVERWRITE bool "Allow unauthenticated pairing with same peer with other local identity" depends on !BT_SMP_ALLOW_UNAUTH_OVERWRITE diff --git a/subsys/bluetooth/host/adv.c b/subsys/bluetooth/host/adv.c index 3a17a7192535..e4ad43bea565 100644 --- a/subsys/bluetooth/host/adv.c +++ b/subsys/bluetooth/host/adv.c @@ -234,25 +234,6 @@ struct bt_le_ext_adv *bt_hci_adv_lookup_handle(uint8_t handle) #endif /* CONFIG_BT_BROADCASTER */ #endif /* defined(CONFIG_BT_EXT_ADV) */ -struct bt_le_ext_adv *bt_adv_lookup_by_id(uint8_t id) -{ -#if defined(CONFIG_BT_EXT_ADV) - for (size_t i = 0; i < ARRAY_SIZE(adv_pool); i++) { - if (atomic_test_bit(adv_pool[i].flags, BT_ADV_CREATED) && - adv_pool[i].id == id) { - return &adv_pool[i]; - } - } -#else - if (atomic_test_bit(bt_dev.adv.flags, BT_ADV_CREATED) && bt_dev.adv.id == id) { - return &bt_dev.adv; - } -#endif - - return NULL; -} - - void bt_le_ext_adv_foreach(void (*func)(struct bt_le_ext_adv *adv, void *data), void *data) { @@ -948,14 +929,6 @@ static int adv_start_legacy(struct bt_le_ext_adv *adv, adv->id = param->id; bt_dev.adv_conn_id = adv->id; - if (IS_ENABLED(CONFIG_BT_ID_AUTO_SWAP_MATCHING_BONDS)) { - err = bt_id_resolving_list_check_and_update(adv->id, param->peer); - if (err) { - LOG_ERR("Failed to check and update resolving list: %d", err); - return err; - } - } - err = bt_id_set_adv_own_addr(adv, param->options, dir_adv, &set_param.own_addr_type); if (err) { @@ -1239,15 +1212,6 @@ int bt_le_adv_start_ext(struct bt_le_ext_adv *adv, } adv->id = param->id; - - if (IS_ENABLED(CONFIG_BT_ID_AUTO_SWAP_MATCHING_BONDS)) { - err = bt_id_resolving_list_check_and_update(adv->id, param->peer); - if (err) { - LOG_ERR("Failed to check and update resolving list: %d", err); - return err; - } - } - err = le_ext_adv_param_set(adv, param, sd != NULL); if (err) { return err; @@ -1535,22 +1499,6 @@ int bt_le_ext_adv_start(struct bt_le_ext_adv *adv, return -EALREADY; } - if (IS_ENABLED(CONFIG_BT_ID_AUTO_SWAP_MATCHING_BONDS)) { - const bt_addr_le_t *peer; - - if (bt_addr_le_eq(&adv->target_addr, BT_ADDR_LE_ANY)) { - peer = NULL; - } else { - peer = &adv->target_addr; - } - - err = bt_id_resolving_list_check_and_update(adv->id, peer); - if (err) { - LOG_ERR("Failed to check and update resolving list: %d", err); - return err; - } - } - if (IS_ENABLED(CONFIG_BT_PERIPHERAL) && atomic_test_bit(adv->flags, BT_ADV_CONNECTABLE)) { err = le_adv_start_add_conn(adv, &conn); diff --git a/subsys/bluetooth/host/adv.h b/subsys/bluetooth/host/adv.h index a6f7007f64b4..6cc950fe8e7f 100644 --- a/subsys/bluetooth/host/adv.h +++ b/subsys/bluetooth/host/adv.h @@ -23,4 +23,3 @@ int bt_le_adv_set_enable_ext(struct bt_le_ext_adv *adv, int bt_le_adv_set_enable_legacy(struct bt_le_ext_adv *adv, bool enable); int bt_le_lim_adv_cancel_timeout(struct bt_le_ext_adv *adv); void bt_adv_reset_adv_pool(void); -struct bt_le_ext_adv *bt_adv_lookup_by_id(uint8_t id); diff --git a/subsys/bluetooth/host/hci_core.h b/subsys/bluetooth/host/hci_core.h index e17277ba4da2..e4a390af20aa 100644 --- a/subsys/bluetooth/host/hci_core.h +++ b/subsys/bluetooth/host/hci_core.h @@ -497,28 +497,7 @@ struct bt_keys; void bt_id_add(struct bt_keys *keys); void bt_id_del(struct bt_keys *keys); -/** @brief Find a conflict in the resolving list for a candidate IRK. - * - * @param candidate The candidate keys to check for conflicts. - * @param all If true, check all IRKs, otherwise check only added keys. - * - * @return The conflicting key if there is one, or NULL if no conflict was found. - */ -struct bt_keys *bt_id_find_conflict(struct bt_keys *candidate, bool all); - -/** * @brief Find multiple conflicts in the resolving list for a candidate IRK. - * - * This function iterates over all keys (added and not added to the Resolving List). If there are - * multiple conflicts, this function will return true. Otherwise, it will return false. - * - * If @c firt_conflict is not NULL, it will be set to the first found conflict. - * - * @param candidate The candidate key to check for conflicts. - * @param first_conflict Pointer to store the first found conflict, if any. Can be NULL. - * - * @return True if there are multiple conflicts, otherwise it returns false. - */ -bool bt_id_find_conflict_multiple(struct bt_keys *candidate, struct bt_keys **first_conflict); +struct bt_keys *bt_id_find_conflict(struct bt_keys *candidate); int bt_setup_random_id_addr(void); int bt_setup_public_id_addr(void); diff --git a/subsys/bluetooth/host/id.c b/subsys/bluetooth/host/id.c index 4c54460ab4df..0ed84dff7331 100644 --- a/subsys/bluetooth/host/id.c +++ b/subsys/bluetooth/host/id.c @@ -941,33 +941,9 @@ void bt_id_pending_keys_update(void) } } -static bool keys_conflict_check(const struct bt_keys *candidate, const struct bt_keys *resident) -{ - bool addr_conflict; - bool irk_conflict; - - addr_conflict = bt_addr_le_eq(&candidate->addr, &resident->addr); - - /* All-zero IRK is "no IRK", and does not conflict with other Zero-IRKs. */ - irk_conflict = (!bt_irk_eq(&candidate->irk, &(struct bt_irk){}) && - bt_irk_eq(&candidate->irk, &resident->irk)); - - if (addr_conflict || irk_conflict) { - LOG_DBG("Resident : addr %s and IRK %s", bt_addr_le_str(&resident->addr), - bt_hex(resident->irk.val, sizeof(resident->irk.val))); - LOG_DBG("Candidate: addr %s and IRK %s", bt_addr_le_str(&candidate->addr), - bt_hex(candidate->irk.val, sizeof(candidate->irk.val))); - - return true; - } - - return false; -} - struct bt_id_conflict { struct bt_keys *candidate; struct bt_keys *found; - bool check_all_irk; }; /* The Controller Resolve List is constrained by 7.8.38 "LE Add Device To @@ -979,6 +955,8 @@ struct bt_id_conflict { static 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); @@ -991,26 +969,32 @@ static void find_rl_conflict(struct bt_keys *resident, void *user_data) } /* Test against committed bonds only. */ - if (!conflict->check_all_irk && (resident->state & BT_KEYS_ID_ADDED) == 0) { - /* If the resident bond is not committed, we cannot have a conflict. */ + if ((resident->state & BT_KEYS_ID_ADDED) == 0) { return; } - if (resident->id == conflict->candidate->id) { - /* If the IDs are the same, we cannot have a conflict. */ - 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) { + LOG_DBG("Resident : addr %s and IRK %s, id: %d", bt_addr_le_str(&resident->addr), + bt_hex(resident->irk.val, sizeof(resident->irk.val)), resident->id); + LOG_DBG("Candidate: addr %s and IRK %s, id: %d", + bt_addr_le_str(&conflict->candidate->addr), + bt_hex(conflict->candidate->irk.val, sizeof(conflict->candidate->irk.val)), + conflict->candidate->id); - if (keys_conflict_check(conflict->candidate, resident)) { conflict->found = resident; } } -struct bt_keys *bt_id_find_conflict(struct bt_keys *candidate, bool check_all_irk) +struct bt_keys *bt_id_find_conflict(struct bt_keys *candidate) { struct bt_id_conflict conflict = { .candidate = candidate, - .check_all_irk = check_all_irk, }; bt_keys_foreach_type(BT_KEYS_IRK, find_rl_conflict, &conflict); @@ -1018,59 +1002,6 @@ struct bt_keys *bt_id_find_conflict(struct bt_keys *candidate, bool check_all_ir return conflict.found; } -struct bt_id_conflict_multiple { - struct bt_keys *candidate; - struct bt_keys *found; - bool found_multiple; -}; - -void find_rl_conflict_multiple(struct bt_keys *resident, void *user_data) -{ - struct bt_id_conflict_multiple *conflict = user_data; - - __ASSERT_NO_MSG(conflict != NULL); - __ASSERT_NO_MSG(conflict->candidate != NULL); - __ASSERT_NO_MSG(resident != NULL); - - if (conflict->found_multiple) { - /* If we already found enough conflicts, we can stop searching. */ - return; - } - - if (resident->id == conflict->candidate->id) { - /* If the IDs are the same, we cannot have a conflict. */ - return; - } - - if (keys_conflict_check(conflict->candidate, resident)) { - if (conflict->found) { - conflict->found_multiple = true; - - LOG_WRN("Found multiple conflicts for %s: addr %s and IRK %s", - bt_addr_le_str(&conflict->candidate->addr), - bt_addr_le_str(&resident->addr), - bt_hex(resident->irk.val, sizeof(resident->irk.val))); - } else { - conflict->found = resident; - } - } -} - -bool bt_id_find_conflict_multiple(struct bt_keys *candidate, struct bt_keys **first_conflict) -{ - struct bt_id_conflict_multiple conflict = { - .candidate = candidate, - }; - - bt_keys_foreach_type(BT_KEYS_IRK, find_rl_conflict_multiple, &conflict); - - if (first_conflict != NULL) { - *first_conflict = conflict.found; - } - - return conflict.found_multiple; -} - void bt_id_add(struct bt_keys *keys) { CHECKIF(keys == NULL) { @@ -1333,122 +1264,6 @@ void bt_id_del(struct bt_keys *keys) bt_le_ext_adv_foreach(adv_unpause_enabled, NULL); } } - -static int conflict_check_and_replace(uint8_t id, struct bt_keys *keys) -{ - /* For the given key check if it has conflicts with other keys in the Resolving List - * (such keys have BT_KEYS_ID_ADDED state and BT_KEYS_ID_CONFLICT flag set). If it does, we - * need to remove the conflicting key from the Resolving List and add the new key. - * - * If the key is not in the Resolving List, we can add the new key right away. - * - * If advertiser for the conflicting key is enabled, we cannot remove the key from the - * Resolving List, so we return an error. - */ - - struct bt_keys *conflict; - const struct bt_le_ext_adv *adv; - - if (!(keys->flags & BT_KEYS_ID_CONFLICT)) { - LOG_DBG("Key has no conflicts for id %u addr %s", id, bt_addr_le_str(&keys->addr)); - return 0; - } - - if (keys->state & BT_KEYS_ID_ADDED) { - LOG_DBG("Key is already added to resolving list for id %u addr %s", id, - bt_addr_le_str(&keys->addr)); - return 0; - } - - /* bt_id_find_conflict returns only keys added to the Resolving List (state is - * BT_KEYS_ID_ADDED). If the key has conflict, but no keys were added (for example, if the - * last added key was removed after bt_unpair()), then this function will return NULL. Then, - * we don't need to remove a conflicting key from the Resolving List. Otherwise, we need to - * remove the conflicting key from the Resolving List before adding the new key. - */ - conflict = bt_id_find_conflict(keys, false); - if (conflict != NULL) { - __ASSERT_NO_MSG((conflict->flags & BT_KEYS_ID_CONFLICT) != 0); - - LOG_DBG("Found conflicting key with id %u addr %s", conflict->id, - bt_addr_le_str(&conflict->addr)); - - adv = bt_adv_lookup_by_id(conflict->id); - if (adv && atomic_test_bit(adv->flags, BT_ADV_ENABLED)) { - LOG_WRN("Cannot remove the conflicting key from the Resolving List while" - " advertising"); - return -EPERM; - } - - /* Drop BT_KEYS_ID_PENDING_DEL flag if we were about to delete the keys since we - * delete it here. - */ - conflict->state &= ~BT_KEYS_ID_PENDING_DEL; - bt_id_del(conflict); - } - - bt_id_add(keys); - - return 0; -} - -struct bt_id_resolve { - uint8_t id; - int err; -}; - -static void check_and_add_keys_for_id(struct bt_keys *keys, void *data) -{ - struct bt_id_resolve *resolve = data; - - if (resolve->err) { - /* Skipping other keys because we got error. */ - return; - } - - if (resolve->id != keys->id) { - /* We are only interested in keys for the given id */ - return; - } - - resolve->err = conflict_check_and_replace(resolve->id, keys); -} - -int bt_id_resolving_list_check_and_update(uint8_t id, const bt_addr_le_t *peer) -{ - int err; - - if (peer == NULL) { - struct bt_id_resolve resolve = { - .id = id, - }; - - LOG_DBG("Updating resolving list for id %u without peer address", id); - - bt_keys_foreach_type(BT_KEYS_IRK, check_and_add_keys_for_id, &resolve); - err = resolve.err; - } else { - struct bt_keys *keys; - - LOG_DBG("Updating resolving list for id %u addr %s", id, bt_addr_le_str(peer)); - - keys = bt_keys_get_addr(id, peer); - if (!keys) { - LOG_DBG("No keys found for id %u addr %s", id, bt_addr_le_str(peer)); - return -ENOENT; - } - - err = conflict_check_and_replace(id, keys); - } - - if (err) { - LOG_ERR("Failed to update resolving list for id %u addr %s (err %d)", id, - peer ? bt_addr_le_str(peer) : "NULL", err); - return err; - } - - return err; -} #endif /* defined(CONFIG_BT_SMP) */ void bt_id_get(bt_addr_le_t *addrs, size_t *count) diff --git a/subsys/bluetooth/host/id.h b/subsys/bluetooth/host/id.h index cd66784a5037..8824d3bb496b 100644 --- a/subsys/bluetooth/host/id.h +++ b/subsys/bluetooth/host/id.h @@ -60,26 +60,3 @@ void bt_id_pending_keys_update(void); void bt_id_pending_keys_update_set(struct bt_keys *keys, uint8_t flag); void bt_id_adv_limited_stopped(struct bt_le_ext_adv *adv); - -/** - * @brief Check and update the resolving list for a given identity. - * - * This function checks if the resolving list contains the keys for the given - * identity and peer address. If the keys are not present, it adds them to the - * resolving list. If the keys are present, it checks for conflicts with - * existing keys in the resolving list. If a conflict is found, it replaces - * the conflicting key with the new key. - * - * If the peer address is NULL, it updates the resolving list for all keys that belong to the given - * identity. - * - * If for any of the keys belonging to the given identity a conflict is found and the advertiser for - * that key is enabled, the function returns an error. - * - * @param id The identity ID to check and update. - * @param peer The peer address to check against the resolving list. - * - * @return 0 on success, or a negative error code on failure. - * @return -EPERM if a conflict is found and the advertiser for the conflicting key is enabled. - */ -int bt_id_resolving_list_check_and_update(uint8_t id, const bt_addr_le_t *peer); diff --git a/subsys/bluetooth/host/keys.c b/subsys/bluetooth/host/keys.c index e2116f3bedeb..1205494e856f 100644 --- a/subsys/bluetooth/host/keys.c +++ b/subsys/bluetooth/host/keys.c @@ -310,57 +310,16 @@ void bt_keys_add_type(struct bt_keys *keys, enum bt_keys_type type) keys->keys |= type; } -static void add_id_cb(struct k_work *work) -{ - bt_id_pending_keys_update(); -} - -static K_WORK_DEFINE(add_id_work, add_id_cb); - void bt_keys_clear(struct bt_keys *keys) { - struct bt_keys *conflict = NULL; - __ASSERT_NO_MSG(keys != NULL); LOG_DBG("%s (keys 0x%04x)", bt_addr_le_str(&keys->addr), keys->keys); - if (IS_ENABLED(CONFIG_BT_ID_AUTO_SWAP_MATCHING_BONDS) && - (keys->flags & BT_KEYS_ID_CONFLICT) != 0) { - /* We need to check how many conflicting keys left. If there is only one conflicting - * key left, we can remove the BT_KEYS_ID_CONFLICT flag from it so that Host don't - * need to check and update the Resolving List whenever this is needed. The key - * should be re-added to the Resolving List. - */ - bool found_multiple; - - found_multiple = bt_id_find_conflict_multiple(keys, &conflict); - if (conflict) { - if (found_multiple || (conflict->state & BT_KEYS_ID_ADDED) != 0) { - /* If we found multiple conflicting keys or the conflicting key - * is already added to the ID list, we don't need to clear the - * conflict flag for it and re-add it to the Resolving List. - */ - conflict = NULL; - } else { - /* Clear the conflict flag for the conflicting key */ - conflict->flags &= ~BT_KEYS_ID_CONFLICT; - } - } - } - if (keys->state & BT_KEYS_ID_ADDED) { bt_id_del(keys); } - if (conflict) { - /* Re-add the conflicting key to the Resolving List if it was the last conflicting - * key. - */ - bt_id_pending_keys_update_set(conflict, BT_KEYS_ID_PENDING_ADD); - k_work_submit(&add_id_work); - } - if (IS_ENABLED(CONFIG_BT_SETTINGS)) { /* Delete stored keys from flash */ bt_settings_delete_keys(keys->id, &keys->addr); @@ -388,28 +347,6 @@ int bt_keys_store(struct bt_keys *keys) return 0; } -static void check_and_set_id_conflict_flag(struct bt_keys *keys) -{ - struct bt_keys *conflict; - - if (!IS_ENABLED(CONFIG_BT_ID_AUTO_SWAP_MATCHING_BONDS)) { - /* If auto-swap is not enabled, we don't need to check for conflicts */ - return; - } - - /* Use bt_id_find_conflict() to check if there are any conflicting keys for the given keys. - * If there is at least one, set the BT_KEYS_ID_CONFLICT flag for both the keys and the - * conflicting key. - */ - conflict = bt_id_find_conflict(keys, true); - if (conflict != NULL) { - LOG_DBG("Found conflicting key %p.", conflict); - - keys->flags |= BT_KEYS_ID_CONFLICT; - conflict->flags |= BT_KEYS_ID_CONFLICT; - } -} - static int keys_set(const char *name, size_t len_rd, settings_read_cb read_cb, void *cb_arg) { @@ -490,8 +427,6 @@ static int keys_set(const char *name, size_t len_rd, settings_read_cb read_cb, memcpy(keys->storage_start, val, len); } - check_and_set_id_conflict_flag(keys); - LOG_DBG("Successfully restored keys for %s", bt_addr_le_str(&addr)); #if defined(CONFIG_BT_KEYS_OVERWRITE_OLDEST) if (aging_counter_val < keys->aging_counter) { @@ -501,17 +436,17 @@ static int keys_set(const char *name, size_t len_rd, settings_read_cb read_cb, return 0; } +static void add_id_cb(struct k_work *work) +{ + bt_id_pending_keys_update(); +} + +static K_WORK_DEFINE(add_id_work, add_id_cb); + static void id_add(struct bt_keys *keys, void *user_data) { __ASSERT_NO_MSG(keys != NULL); - if (keys->flags & BT_KEYS_ID_CONFLICT) { - /* If the keys have the conflict flag set, we don't want to add them to the ID list, - * as this will cause issues with resolving list. - */ - return; - } - bt_id_pending_keys_update_set(keys, BT_KEYS_ID_PENDING_ADD); k_work_submit(&add_id_work); } diff --git a/subsys/bluetooth/host/keys.h b/subsys/bluetooth/host/keys.h index 90c0c92e9de0..ab83aff8ebf0 100644 --- a/subsys/bluetooth/host/keys.h +++ b/subsys/bluetooth/host/keys.h @@ -45,12 +45,6 @@ enum { /* Bit 2 and 3 might accidentally exist in old stored keys */ BT_KEYS_SC = BIT(4), BT_KEYS_OOB = BIT(5), - /** Indicates that the keys are in conflict with existing keys. - * - * This is used to indicate that the keys being added conflict with - * existing keys from different identity. - */ - BT_KEYS_ID_CONFLICT = BIT(6), }; struct bt_ltk { diff --git a/subsys/bluetooth/host/smp.c b/subsys/bluetooth/host/smp.c index 1e28a4e0c84f..b935c61d2a36 100644 --- a/subsys/bluetooth/host/smp.c +++ b/subsys/bluetooth/host/smp.c @@ -921,7 +921,7 @@ static void smp_br_id_add_replace(struct bt_keys *keys) bt_id_del(keys); } - conflict = bt_id_find_conflict(keys, false); + conflict = bt_id_find_conflict(keys); if (conflict != NULL) { int err; @@ -931,7 +931,7 @@ static void smp_br_id_add_replace(struct bt_keys *keys) __ASSERT_NO_MSG(!err); } - __ASSERT_NO_MSG(!bt_id_find_conflict(keys, false)); + __ASSERT_NO_MSG(!bt_id_find_conflict(keys)); bt_id_add(keys); } @@ -4129,24 +4129,16 @@ static uint8_t smp_id_add_replace(struct bt_smp *smp, struct bt_keys *new_bond) */ __ASSERT_NO_MSG(!(smp->remote_dist & BT_SMP_DIST_ID_KEY)); - conflict = bt_id_find_conflict(new_bond, IS_ENABLED(CONFIG_BT_ID_AUTO_SWAP_MATCHING_BONDS)); + conflict = bt_id_find_conflict(new_bond); if (conflict) { LOG_DBG("New bond conflicts with a bond on id %d.", conflict->id); } - if (conflict && !IS_ENABLED(CONFIG_BT_ID_AUTO_SWAP_MATCHING_BONDS) && - !IS_ENABLED(CONFIG_BT_ID_UNPAIR_MATCHING_BONDS)) { + if (conflict && !IS_ENABLED(CONFIG_BT_ID_UNPAIR_MATCHING_BONDS)) { LOG_WRN("Refusing new pairing. The old bond must be unpaired first."); return BT_SMP_ERR_AUTH_REQUIREMENTS; } - if (conflict && IS_ENABLED(CONFIG_BT_ID_AUTO_SWAP_MATCHING_BONDS)) { - LOG_WRN("Conflict detected with %p. Don't add key to Resolve List.", conflict); - new_bond->flags |= BT_KEYS_ID_CONFLICT; - conflict->flags |= BT_KEYS_ID_CONFLICT; - return 0; - } - if (conflict && IS_ENABLED(CONFIG_BT_ID_UNPAIR_MATCHING_BONDS)) { bool trust_ok; int unpair_err; @@ -4163,7 +4155,7 @@ static uint8_t smp_id_add_replace(struct bt_smp *smp, struct bt_keys *new_bond) __ASSERT_NO_MSG(!unpair_err); } - __ASSERT_NO_MSG(!bt_id_find_conflict(new_bond, false)); + __ASSERT_NO_MSG(!bt_id_find_conflict(new_bond)); bt_id_add(new_bond); return 0; } diff --git a/tests/bluetooth/host/id/mocks/adv.c b/tests/bluetooth/host/id/mocks/adv.c index a22123dea3da..2c2d4f3f3c7a 100644 --- a/tests/bluetooth/host/id/mocks/adv.c +++ b/tests/bluetooth/host/id/mocks/adv.c @@ -15,4 +15,3 @@ DEFINE_FAKE_VALUE_FUNC(int, bt_le_adv_set_enable_legacy, struct bt_le_ext_adv *, DEFINE_FAKE_VALUE_FUNC(int, bt_le_adv_set_enable_ext, struct bt_le_ext_adv *, bool, const struct bt_le_ext_adv_start_param *); DEFINE_FAKE_VOID_FUNC(bt_le_ext_adv_foreach, bt_le_ext_adv_foreach_cb, void *); -DEFINE_FAKE_VALUE_FUNC(struct bt_le_ext_adv *, bt_adv_lookup_by_id, uint8_t); diff --git a/tests/bluetooth/host/id/mocks/adv.h b/tests/bluetooth/host/id/mocks/adv.h index 1602ddf47185..bfb744001596 100644 --- a/tests/bluetooth/host/id/mocks/adv.h +++ b/tests/bluetooth/host/id/mocks/adv.h @@ -18,8 +18,7 @@ typedef void (*bt_le_ext_adv_foreach_cb)(struct bt_le_ext_adv *adv, void *data); FAKE(bt_le_adv_lookup_legacy) \ FAKE(bt_le_ext_adv_get_index) \ FAKE(bt_le_adv_set_enable_ext) \ - FAKE(bt_le_ext_adv_foreach) \ - FAKE(bt_adv_lookup_by_id) + FAKE(bt_le_ext_adv_foreach) DECLARE_FAKE_VALUE_FUNC(int, bt_le_adv_set_enable, struct bt_le_ext_adv *, bool); DECLARE_FAKE_VALUE_FUNC(struct bt_le_ext_adv *, bt_le_adv_lookup_legacy); @@ -28,4 +27,3 @@ DECLARE_FAKE_VALUE_FUNC(int, bt_le_adv_set_enable_legacy, struct bt_le_ext_adv * DECLARE_FAKE_VALUE_FUNC(int, bt_le_adv_set_enable_ext, struct bt_le_ext_adv *, bool, const struct bt_le_ext_adv_start_param *); DECLARE_FAKE_VOID_FUNC(bt_le_ext_adv_foreach, bt_le_ext_adv_foreach_cb, void *); -DECLARE_FAKE_VALUE_FUNC(struct bt_le_ext_adv *, bt_adv_lookup_by_id, uint8_t); diff --git a/tests/bluetooth/host/id/mocks/keys.c b/tests/bluetooth/host/id/mocks/keys.c index 61f73569c469..f885ab875c0f 100644 --- a/tests/bluetooth/host/id/mocks/keys.c +++ b/tests/bluetooth/host/id/mocks/keys.c @@ -10,4 +10,3 @@ DEFINE_FAKE_VALUE_FUNC(struct bt_keys *, bt_keys_find_irk, uint8_t, const bt_addr_le_t *); DEFINE_FAKE_VOID_FUNC(bt_keys_foreach_type, enum bt_keys_type, bt_keys_foreach_type_cb, void *); -DEFINE_FAKE_VALUE_FUNC(struct bt_keys *, bt_keys_get_addr, uint8_t, const bt_addr_le_t *); diff --git a/tests/bluetooth/host/id/mocks/keys.h b/tests/bluetooth/host/id/mocks/keys.h index 1912472b78de..b6901e315ab9 100644 --- a/tests/bluetooth/host/id/mocks/keys.h +++ b/tests/bluetooth/host/id/mocks/keys.h @@ -15,9 +15,7 @@ typedef void (*bt_keys_foreach_type_cb)(struct bt_keys *keys, void *data); /* List of fakes used by this unit tester */ #define KEYS_FFF_FAKES_LIST(FAKE) \ FAKE(bt_keys_find_irk) \ - FAKE(bt_keys_foreach_type) \ - FAKE(bt_keys_get_addr) + FAKE(bt_keys_foreach_type) DECLARE_FAKE_VALUE_FUNC(struct bt_keys *, bt_keys_find_irk, uint8_t, const bt_addr_le_t *); DECLARE_FAKE_VOID_FUNC(bt_keys_foreach_type, enum bt_keys_type, bt_keys_foreach_type_cb, void *); -DECLARE_FAKE_VALUE_FUNC(struct bt_keys *, bt_keys_get_addr, uint8_t, const bt_addr_le_t *); From 51dcb3bf3cfad5667339850551123f337a562127 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5vard=20Reierstad?= Date: Tue, 18 Nov 2025 12:15:16 +0100 Subject: [PATCH 2/4] [nrf fromtree] Bluetooth: Host: Legacy passkey entry 6.2 update MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As of Core v6.2, the passkey entry pairing method for legacy pairing does no longer grant authenticated MITM protection. This commit updates `smp.c` accordingly to not grant the authenticated states when using legacy passkey entry pairing. Adds a check to make sure that bonds that have been stored persistently adheres to these changes. Bonds that have been generated using the legacy passkey entry pairing method will thus be downgraded from authenticated to unauthenticated when restored from storage. Signed-off-by: Håvard Reierstad (cherry picked from commit 627b6e4dd72bf4481fa8ff7dfee8dbf38e5e934b) Signed-off-by: Håvard Reierstad --- doc/releases/migration-guide-4.4.rst | 4 ++++ subsys/bluetooth/host/keys.c | 12 ++++++++++++ subsys/bluetooth/host/smp.c | 25 +++++++++++++++++-------- 3 files changed, 33 insertions(+), 8 deletions(-) diff --git a/doc/releases/migration-guide-4.4.rst b/doc/releases/migration-guide-4.4.rst index 554607e5f857..762082635b1c 100644 --- a/doc/releases/migration-guide-4.4.rst +++ b/doc/releases/migration-guide-4.4.rst @@ -43,6 +43,10 @@ Bluetooth Host * :c:member:`bt_conn_le_info.interval` has been deprecated. Use :c:member:`bt_conn_le_info.interval_us` instead. Note that the units have changed: ``interval`` was in units of 1.25 milliseconds, while ``interval_us`` is in microseconds. +* Legacy Bluetooth LE pairing using the passkey entry method no longer grants authenticated (MITM) + protection as of the Bluetooth Core Specification v6.2. Stored bonds that were generated using + this method will be downgraded to unauthenticated when loaded from persistent storage, resulting + in a lower security level. Networking ********** diff --git a/subsys/bluetooth/host/keys.c b/subsys/bluetooth/host/keys.c index 1205494e856f..0ab157599408 100644 --- a/subsys/bluetooth/host/keys.c +++ b/subsys/bluetooth/host/keys.c @@ -427,6 +427,18 @@ static int keys_set(const char *name, size_t len_rd, settings_read_cb read_cb, memcpy(keys->storage_start, val, len); } + /* As of Core v6.2, authenticated keys are only valid for OOB or LE SC pairing + * methods. This check ensures that keys are valid if a device is updated from a + * previous version that did not enforce this requirement. + */ + if ((keys->flags & BT_KEYS_AUTHENTICATED) && + !((keys->flags & BT_KEYS_OOB) || (keys->flags & BT_KEYS_SC))) { + LOG_WRN("The keys for %s are downgraded to unauthenticated as they no longer meet " + "authentication requirements", + bt_addr_le_str(&addr)); + keys->flags &= ~BT_KEYS_AUTHENTICATED; + } + LOG_DBG("Successfully restored keys for %s", bt_addr_le_str(&addr)); #if defined(CONFIG_BT_KEYS_OVERWRITE_OLDEST) if (aging_counter_val < keys->aging_counter) { diff --git a/subsys/bluetooth/host/smp.c b/subsys/bluetooth/host/smp.c index b935c61d2a36..94e38d766897 100644 --- a/subsys/bluetooth/host/smp.c +++ b/subsys/bluetooth/host/smp.c @@ -666,7 +666,9 @@ static bool update_keys_check(struct bt_smp *smp, struct bt_keys *keys) } if ((keys->flags & BT_KEYS_AUTHENTICATED) && - smp->method == JUST_WORKS) { + ((smp->method == JUST_WORKS) || + (!atomic_test_bit(smp->flags, SMP_FLAG_SC) && + (smp->method == PASSKEY_DISPLAY || smp->method == PASSKEY_INPUT)))) { return false; } @@ -2491,11 +2493,12 @@ static uint8_t legacy_request_tk(struct bt_smp *smp) * Fail if we have keys that are stronger than keys that will be * distributed in new pairing. This is to avoid replacing authenticated * keys with unauthenticated ones. - */ + */ keys = bt_keys_find_addr(conn->id, &conn->le.dst); if (keys && (keys->flags & BT_KEYS_AUTHENTICATED) && - smp->method == JUST_WORKS) { - LOG_ERR("JustWorks failed, authenticated keys present"); + (smp->method == JUST_WORKS || smp->method == PASSKEY_DISPLAY || + smp->method == PASSKEY_INPUT)) { + LOG_ERR("Pairing failed, authenticated keys present"); return BT_SMP_ERR_UNSPECIFIED; } @@ -2983,7 +2986,9 @@ static uint8_t remote_sec_level_reachable(struct bt_smp *smp) } __fallthrough; case BT_SECURITY_L3: - if (smp->method == JUST_WORKS) { + if (smp->method == JUST_WORKS || + (!atomic_test_bit(smp->flags, SMP_FLAG_SC) && + (smp->method == PASSKEY_DISPLAY || smp->method == PASSKEY_INPUT))) { return BT_SMP_ERR_AUTH_REQUIREMENTS; } @@ -6319,12 +6324,16 @@ void bt_smp_update_keys(struct bt_conn *conn) case LE_SC_OOB: case LEGACY_OOB: conn->le.keys->flags |= BT_KEYS_OOB; - /* fallthrough */ + conn->le.keys->flags |= BT_KEYS_AUTHENTICATED; + break; case PASSKEY_DISPLAY: case PASSKEY_INPUT: case PASSKEY_CONFIRM: - conn->le.keys->flags |= BT_KEYS_AUTHENTICATED; - break; + if (atomic_test_bit(smp->flags, SMP_FLAG_SC)) { + conn->le.keys->flags |= BT_KEYS_AUTHENTICATED; + break; + } + /* fallthrough */ case JUST_WORKS: default: /* unauthenticated key, clear it */ From aac20e6ba02e0cb024e6de3913bffbbc96f0d1ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5vard=20Reierstad?= Date: Thu, 20 Nov 2025 14:00:45 +0100 Subject: [PATCH 3/4] [nrf fromtree] Bluetooth: Host: Add legacy pairing test config MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds the `CONFIG_BT_SMP_LEGACY_PAIR_ONLY` Kconfig option to force devices to use legacy pairing. This has a dependency on `CONFIG_BT_TESTING` as it is only intended for testing purposes, and use of legacy pairing is discouraged. Signed-off-by: Håvard Reierstad (cherry picked from commit 6bb0e982ad5452101b7b7cd34d152fd60c59e74f) Signed-off-by: Håvard Reierstad --- subsys/bluetooth/host/Kconfig | 9 +++++++++ subsys/bluetooth/host/smp.c | 11 ++++++----- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/subsys/bluetooth/host/Kconfig b/subsys/bluetooth/host/Kconfig index 8920d41d0e07..7306cde7328f 100644 --- a/subsys/bluetooth/host/Kconfig +++ b/subsys/bluetooth/host/Kconfig @@ -1120,6 +1120,15 @@ config BT_CONN_DISABLE_SECURITY WARNING: This option enables anyone to snoop on-air traffic. Use of this feature in production is strongly discouraged. +config BT_SMP_LEGACY_PAIR_ONLY + bool "Force legacy pairing" + depends on BT_TESTING + depends on !(BT_SMP_SC_PAIR_ONLY || BT_SMP_SC_ONLY) + help + This option enforces legacy pairing. This is required for testing + legacy pairing between two Zephyr Bluetooth devices, as without this + option the devices will default to using Secure Connections pairing. + rsource "./classic/Kconfig" config BT_HCI_VS_EVT_USER diff --git a/subsys/bluetooth/host/smp.c b/subsys/bluetooth/host/smp.c index 94e38d766897..1a5592d1d6c2 100644 --- a/subsys/bluetooth/host/smp.c +++ b/subsys/bluetooth/host/smp.c @@ -92,21 +92,21 @@ LOG_MODULE_REGISTER(bt_smp); #if defined(CONFIG_BT_CLASSIC) #define BT_SMP_AUTH_MASK_SC 0x2f -#if defined(CONFIG_BT_SMP_OOB_LEGACY_PAIR_ONLY) +#if defined(CONFIG_BT_SMP_OOB_LEGACY_PAIR_ONLY) || defined(CONFIG_BT_SMP_LEGACY_PAIR_ONLY) #define BT_SMP_AUTH_DEFAULT (BT_SMP_AUTH_BONDING_FLAGS | BT_SMP_AUTH_CT2) #else #define BT_SMP_AUTH_DEFAULT (BT_SMP_AUTH_BONDING_FLAGS | BT_SMP_AUTH_CT2 |\ BT_SMP_AUTH_SC) -#endif /* CONFIG_BT_SMP_OOB_LEGACY_PAIR_ONLY */ +#endif /* CONFIG_BT_SMP_OOB_LEGACY_PAIR_ONLY || CONFIG_BT_SMP_LEGACY_PAIR_ONLY */ #else #define BT_SMP_AUTH_MASK_SC 0x0f -#if defined(CONFIG_BT_SMP_OOB_LEGACY_PAIR_ONLY) +#if defined(CONFIG_BT_SMP_OOB_LEGACY_PAIR_ONLY) || defined(CONFIG_BT_SMP_LEGACY_PAIR_ONLY) #define BT_SMP_AUTH_DEFAULT (BT_SMP_AUTH_BONDING_FLAGS) #else #define BT_SMP_AUTH_DEFAULT (BT_SMP_AUTH_BONDING_FLAGS | BT_SMP_AUTH_SC) -#endif /* CONFIG_BT_SMP_OOB_LEGACY_PAIR_ONLY */ +#endif /* CONFIG_BT_SMP_OOB_LEGACY_PAIR_ONLY || CONFIG_BT_SMP_LEGACY_PAIR_ONLY */ #endif /* CONFIG_BT_CLASSIC */ @@ -321,7 +321,8 @@ static struct { static bool le_sc_supported(void) { - if (IS_ENABLED(CONFIG_BT_SMP_OOB_LEGACY_PAIR_ONLY)) { + if (IS_ENABLED(CONFIG_BT_SMP_OOB_LEGACY_PAIR_ONLY) || + IS_ENABLED(CONFIG_BT_SMP_LEGACY_PAIR_ONLY)) { return false; } From c268343695d3c4eceabf6be42d4046929ca471f0 Mon Sep 17 00:00:00 2001 From: Pavel Vasilyev Date: Tue, 10 Jun 2025 23:20:32 +0200 Subject: [PATCH 4/4] [nrf noup] bluetooth: host: Add support for bonding with same peer This commit adds a new Kconfig option by enabling which Host will keep bonding with the same Central instead of rejecting pairing. Brief implementation details: This implementation adds a new flag to bt_keys struct: BT_KEYS_ID_CONFLICT. The flag is set, when: - bonding with the same peer and conflict identified - when loading conflicting keys from persistent storage. When bonding and conflict is identified, the new keys aren't added to the Resolving List immediately. Instead, the old keys stay in the Resolving List. When start advertising, Host finds conflicting keys that are already added to the Resolving List and substitues them. If, however, there is another advertiser already started for the added keys, the new request is reject and advertising start function returns -EPERM. This is supported by Peripheral role only for now. Allow to use CONFIG_BT_ID_AUTO_SWAP_MATCHING_BONDS Kconfig option even if CONFIG_BT_PRIVACY is disabled. This is because CONFIG_BT_PRIVACY configures privacy of local device will still allows to resolve peer address. During pairing, peer device may send its Identity Address and IRK which then can be used for address resolution. This doesn't require CONFIG_BT_PRIVACY be enabled. Signed-off-by: Pavel Vasilyev (cherry picked from commit 8e030eadc7edc6b92ea0812b4ba85943b361765c) (cherry picked from commit 72becd444df29326d03f7374c21f0e73e3641ac1) (cherry picked from commit 4994883cb4f5b53f64c5909798a5dfd6ee79e376) --- include/zephyr/bluetooth/bluetooth.h | 10 ++ subsys/bluetooth/host/Kconfig | 18 +++ subsys/bluetooth/host/adv.c | 52 +++++++ subsys/bluetooth/host/adv.h | 1 + subsys/bluetooth/host/hci_core.h | 23 ++- subsys/bluetooth/host/id.c | 219 ++++++++++++++++++++++++--- subsys/bluetooth/host/id.h | 23 +++ subsys/bluetooth/host/keys.c | 79 +++++++++- subsys/bluetooth/host/keys.h | 6 + subsys/bluetooth/host/smp.c | 18 ++- tests/bluetooth/host/id/mocks/adv.c | 1 + tests/bluetooth/host/id/mocks/adv.h | 4 +- tests/bluetooth/host/id/mocks/keys.c | 1 + tests/bluetooth/host/id/mocks/keys.h | 4 +- 14 files changed, 427 insertions(+), 32 deletions(-) diff --git a/include/zephyr/bluetooth/bluetooth.h b/include/zephyr/bluetooth/bluetooth.h index 8e738d21970d..0739733c9543 100644 --- a/include/zephyr/bluetooth/bluetooth.h +++ b/include/zephyr/bluetooth/bluetooth.h @@ -1295,6 +1295,10 @@ struct bt_le_per_adv_param { * This error code is only guaranteed when using Zephyr * controller, for other controllers code returned in * this case may be -EIO. + * @return -EPERM When @kconfig{CONFIG_BT_PRIVACY} and + * @kconfig{CONFIG_BT_ID_AUTO_SWAP_MATCHING_BONDS} are enabled and connectable + * advertising is requested, and the given local identity has a conflicting + * key with another local identity for which advertising is already started. */ int bt_le_adv_start(const struct bt_le_adv_param *param, const struct bt_data *ad, size_t ad_len, @@ -1422,6 +1426,12 @@ struct bt_le_ext_adv_start_param { * * @param adv Advertising set object. * @param param Advertise start parameters. + * + * @return Zero on success or (negative) error code otherwise. + * @return -EPERM When @kconfig{CONFIG_BT_PRIVACY} and + * @kconfig{CONFIG_BT_ID_AUTO_SWAP_MATCHING_BONDS} are enabled and connectable + * advertising is requested, and the given local identity has a conflicting + * key with another local identity for which advertising is already started. */ int bt_le_ext_adv_start(struct bt_le_ext_adv *adv, const struct bt_le_ext_adv_start_param *param); diff --git a/subsys/bluetooth/host/Kconfig b/subsys/bluetooth/host/Kconfig index 7306cde7328f..e4a381e9b05a 100644 --- a/subsys/bluetooth/host/Kconfig +++ b/subsys/bluetooth/host/Kconfig @@ -659,6 +659,24 @@ config BT_ID_UNPAIR_MATCHING_BONDS link-layer. The Host does not have control over this acknowledgment, and the order of distribution is fixed by the specification. +config BT_ID_AUTO_SWAP_MATCHING_BONDS + bool "Automatically swap conflicting entries in the Resolving List" + depends on !BT_ID_UNPAIR_MATCHING_BONDS + depends on BT_SMP && BT_PERIPHERAL && !BT_CENTRAL + help + If this option is enabled, the Host will not add a new bond with + the same peer address (or IRK) to the Resolving List if there is + already a bond with the same peer address (or IRK) on another local + identity. + + In case of Peripheral, the Host will swap the existing entry in the + Resolving List with the new one, so that the new bond will be used for + address resolution for the new local identity if the device starts + advertising with the new local identity. + + Important: this option is supported exclusively in the Peripheral + role. Excluding the Central role. + config BT_ID_ALLOW_UNAUTH_OVERWRITE bool "Allow unauthenticated pairing with same peer with other local identity" depends on !BT_SMP_ALLOW_UNAUTH_OVERWRITE diff --git a/subsys/bluetooth/host/adv.c b/subsys/bluetooth/host/adv.c index e4ad43bea565..3a17a7192535 100644 --- a/subsys/bluetooth/host/adv.c +++ b/subsys/bluetooth/host/adv.c @@ -234,6 +234,25 @@ struct bt_le_ext_adv *bt_hci_adv_lookup_handle(uint8_t handle) #endif /* CONFIG_BT_BROADCASTER */ #endif /* defined(CONFIG_BT_EXT_ADV) */ +struct bt_le_ext_adv *bt_adv_lookup_by_id(uint8_t id) +{ +#if defined(CONFIG_BT_EXT_ADV) + for (size_t i = 0; i < ARRAY_SIZE(adv_pool); i++) { + if (atomic_test_bit(adv_pool[i].flags, BT_ADV_CREATED) && + adv_pool[i].id == id) { + return &adv_pool[i]; + } + } +#else + if (atomic_test_bit(bt_dev.adv.flags, BT_ADV_CREATED) && bt_dev.adv.id == id) { + return &bt_dev.adv; + } +#endif + + return NULL; +} + + void bt_le_ext_adv_foreach(void (*func)(struct bt_le_ext_adv *adv, void *data), void *data) { @@ -929,6 +948,14 @@ static int adv_start_legacy(struct bt_le_ext_adv *adv, adv->id = param->id; bt_dev.adv_conn_id = adv->id; + if (IS_ENABLED(CONFIG_BT_ID_AUTO_SWAP_MATCHING_BONDS)) { + err = bt_id_resolving_list_check_and_update(adv->id, param->peer); + if (err) { + LOG_ERR("Failed to check and update resolving list: %d", err); + return err; + } + } + err = bt_id_set_adv_own_addr(adv, param->options, dir_adv, &set_param.own_addr_type); if (err) { @@ -1212,6 +1239,15 @@ int bt_le_adv_start_ext(struct bt_le_ext_adv *adv, } adv->id = param->id; + + if (IS_ENABLED(CONFIG_BT_ID_AUTO_SWAP_MATCHING_BONDS)) { + err = bt_id_resolving_list_check_and_update(adv->id, param->peer); + if (err) { + LOG_ERR("Failed to check and update resolving list: %d", err); + return err; + } + } + err = le_ext_adv_param_set(adv, param, sd != NULL); if (err) { return err; @@ -1499,6 +1535,22 @@ int bt_le_ext_adv_start(struct bt_le_ext_adv *adv, return -EALREADY; } + if (IS_ENABLED(CONFIG_BT_ID_AUTO_SWAP_MATCHING_BONDS)) { + const bt_addr_le_t *peer; + + if (bt_addr_le_eq(&adv->target_addr, BT_ADDR_LE_ANY)) { + peer = NULL; + } else { + peer = &adv->target_addr; + } + + err = bt_id_resolving_list_check_and_update(adv->id, peer); + if (err) { + LOG_ERR("Failed to check and update resolving list: %d", err); + return err; + } + } + if (IS_ENABLED(CONFIG_BT_PERIPHERAL) && atomic_test_bit(adv->flags, BT_ADV_CONNECTABLE)) { err = le_adv_start_add_conn(adv, &conn); diff --git a/subsys/bluetooth/host/adv.h b/subsys/bluetooth/host/adv.h index 6cc950fe8e7f..a6f7007f64b4 100644 --- a/subsys/bluetooth/host/adv.h +++ b/subsys/bluetooth/host/adv.h @@ -23,3 +23,4 @@ int bt_le_adv_set_enable_ext(struct bt_le_ext_adv *adv, int bt_le_adv_set_enable_legacy(struct bt_le_ext_adv *adv, bool enable); int bt_le_lim_adv_cancel_timeout(struct bt_le_ext_adv *adv); void bt_adv_reset_adv_pool(void); +struct bt_le_ext_adv *bt_adv_lookup_by_id(uint8_t id); diff --git a/subsys/bluetooth/host/hci_core.h b/subsys/bluetooth/host/hci_core.h index e4a390af20aa..e17277ba4da2 100644 --- a/subsys/bluetooth/host/hci_core.h +++ b/subsys/bluetooth/host/hci_core.h @@ -497,7 +497,28 @@ struct bt_keys; void bt_id_add(struct bt_keys *keys); void bt_id_del(struct bt_keys *keys); -struct bt_keys *bt_id_find_conflict(struct bt_keys *candidate); +/** @brief Find a conflict in the resolving list for a candidate IRK. + * + * @param candidate The candidate keys to check for conflicts. + * @param all If true, check all IRKs, otherwise check only added keys. + * + * @return The conflicting key if there is one, or NULL if no conflict was found. + */ +struct bt_keys *bt_id_find_conflict(struct bt_keys *candidate, bool all); + +/** * @brief Find multiple conflicts in the resolving list for a candidate IRK. + * + * This function iterates over all keys (added and not added to the Resolving List). If there are + * multiple conflicts, this function will return true. Otherwise, it will return false. + * + * If @c firt_conflict is not NULL, it will be set to the first found conflict. + * + * @param candidate The candidate key to check for conflicts. + * @param first_conflict Pointer to store the first found conflict, if any. Can be NULL. + * + * @return True if there are multiple conflicts, otherwise it returns false. + */ +bool bt_id_find_conflict_multiple(struct bt_keys *candidate, struct bt_keys **first_conflict); int bt_setup_random_id_addr(void); int bt_setup_public_id_addr(void); diff --git a/subsys/bluetooth/host/id.c b/subsys/bluetooth/host/id.c index 0ed84dff7331..4c54460ab4df 100644 --- a/subsys/bluetooth/host/id.c +++ b/subsys/bluetooth/host/id.c @@ -941,9 +941,33 @@ void bt_id_pending_keys_update(void) } } +static bool keys_conflict_check(const struct bt_keys *candidate, const struct bt_keys *resident) +{ + bool addr_conflict; + bool irk_conflict; + + addr_conflict = bt_addr_le_eq(&candidate->addr, &resident->addr); + + /* All-zero IRK is "no IRK", and does not conflict with other Zero-IRKs. */ + irk_conflict = (!bt_irk_eq(&candidate->irk, &(struct bt_irk){}) && + bt_irk_eq(&candidate->irk, &resident->irk)); + + if (addr_conflict || irk_conflict) { + LOG_DBG("Resident : addr %s and IRK %s", bt_addr_le_str(&resident->addr), + bt_hex(resident->irk.val, sizeof(resident->irk.val))); + LOG_DBG("Candidate: addr %s and IRK %s", bt_addr_le_str(&candidate->addr), + bt_hex(candidate->irk.val, sizeof(candidate->irk.val))); + + return true; + } + + return false; +} + struct bt_id_conflict { struct bt_keys *candidate; struct bt_keys *found; + bool check_all_irk; }; /* The Controller Resolve List is constrained by 7.8.38 "LE Add Device To @@ -955,8 +979,6 @@ struct bt_id_conflict { static 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); @@ -969,32 +991,26 @@ static void find_rl_conflict(struct bt_keys *resident, void *user_data) } /* Test against committed bonds only. */ - if ((resident->state & BT_KEYS_ID_ADDED) == 0) { + if (!conflict->check_all_irk && (resident->state & BT_KEYS_ID_ADDED) == 0) { + /* If the resident bond is not committed, we cannot have a conflict. */ 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) { - LOG_DBG("Resident : addr %s and IRK %s, id: %d", bt_addr_le_str(&resident->addr), - bt_hex(resident->irk.val, sizeof(resident->irk.val)), resident->id); - LOG_DBG("Candidate: addr %s and IRK %s, id: %d", - bt_addr_le_str(&conflict->candidate->addr), - bt_hex(conflict->candidate->irk.val, sizeof(conflict->candidate->irk.val)), - conflict->candidate->id); + if (resident->id == conflict->candidate->id) { + /* If the IDs are the same, we cannot have a conflict. */ + return; + } + if (keys_conflict_check(conflict->candidate, resident)) { conflict->found = resident; } } -struct bt_keys *bt_id_find_conflict(struct bt_keys *candidate) +struct bt_keys *bt_id_find_conflict(struct bt_keys *candidate, bool check_all_irk) { struct bt_id_conflict conflict = { .candidate = candidate, + .check_all_irk = check_all_irk, }; bt_keys_foreach_type(BT_KEYS_IRK, find_rl_conflict, &conflict); @@ -1002,6 +1018,59 @@ struct bt_keys *bt_id_find_conflict(struct bt_keys *candidate) return conflict.found; } +struct bt_id_conflict_multiple { + struct bt_keys *candidate; + struct bt_keys *found; + bool found_multiple; +}; + +void find_rl_conflict_multiple(struct bt_keys *resident, void *user_data) +{ + struct bt_id_conflict_multiple *conflict = user_data; + + __ASSERT_NO_MSG(conflict != NULL); + __ASSERT_NO_MSG(conflict->candidate != NULL); + __ASSERT_NO_MSG(resident != NULL); + + if (conflict->found_multiple) { + /* If we already found enough conflicts, we can stop searching. */ + return; + } + + if (resident->id == conflict->candidate->id) { + /* If the IDs are the same, we cannot have a conflict. */ + return; + } + + if (keys_conflict_check(conflict->candidate, resident)) { + if (conflict->found) { + conflict->found_multiple = true; + + LOG_WRN("Found multiple conflicts for %s: addr %s and IRK %s", + bt_addr_le_str(&conflict->candidate->addr), + bt_addr_le_str(&resident->addr), + bt_hex(resident->irk.val, sizeof(resident->irk.val))); + } else { + conflict->found = resident; + } + } +} + +bool bt_id_find_conflict_multiple(struct bt_keys *candidate, struct bt_keys **first_conflict) +{ + struct bt_id_conflict_multiple conflict = { + .candidate = candidate, + }; + + bt_keys_foreach_type(BT_KEYS_IRK, find_rl_conflict_multiple, &conflict); + + if (first_conflict != NULL) { + *first_conflict = conflict.found; + } + + return conflict.found_multiple; +} + void bt_id_add(struct bt_keys *keys) { CHECKIF(keys == NULL) { @@ -1264,6 +1333,122 @@ void bt_id_del(struct bt_keys *keys) bt_le_ext_adv_foreach(adv_unpause_enabled, NULL); } } + +static int conflict_check_and_replace(uint8_t id, struct bt_keys *keys) +{ + /* For the given key check if it has conflicts with other keys in the Resolving List + * (such keys have BT_KEYS_ID_ADDED state and BT_KEYS_ID_CONFLICT flag set). If it does, we + * need to remove the conflicting key from the Resolving List and add the new key. + * + * If the key is not in the Resolving List, we can add the new key right away. + * + * If advertiser for the conflicting key is enabled, we cannot remove the key from the + * Resolving List, so we return an error. + */ + + struct bt_keys *conflict; + const struct bt_le_ext_adv *adv; + + if (!(keys->flags & BT_KEYS_ID_CONFLICT)) { + LOG_DBG("Key has no conflicts for id %u addr %s", id, bt_addr_le_str(&keys->addr)); + return 0; + } + + if (keys->state & BT_KEYS_ID_ADDED) { + LOG_DBG("Key is already added to resolving list for id %u addr %s", id, + bt_addr_le_str(&keys->addr)); + return 0; + } + + /* bt_id_find_conflict returns only keys added to the Resolving List (state is + * BT_KEYS_ID_ADDED). If the key has conflict, but no keys were added (for example, if the + * last added key was removed after bt_unpair()), then this function will return NULL. Then, + * we don't need to remove a conflicting key from the Resolving List. Otherwise, we need to + * remove the conflicting key from the Resolving List before adding the new key. + */ + conflict = bt_id_find_conflict(keys, false); + if (conflict != NULL) { + __ASSERT_NO_MSG((conflict->flags & BT_KEYS_ID_CONFLICT) != 0); + + LOG_DBG("Found conflicting key with id %u addr %s", conflict->id, + bt_addr_le_str(&conflict->addr)); + + adv = bt_adv_lookup_by_id(conflict->id); + if (adv && atomic_test_bit(adv->flags, BT_ADV_ENABLED)) { + LOG_WRN("Cannot remove the conflicting key from the Resolving List while" + " advertising"); + return -EPERM; + } + + /* Drop BT_KEYS_ID_PENDING_DEL flag if we were about to delete the keys since we + * delete it here. + */ + conflict->state &= ~BT_KEYS_ID_PENDING_DEL; + bt_id_del(conflict); + } + + bt_id_add(keys); + + return 0; +} + +struct bt_id_resolve { + uint8_t id; + int err; +}; + +static void check_and_add_keys_for_id(struct bt_keys *keys, void *data) +{ + struct bt_id_resolve *resolve = data; + + if (resolve->err) { + /* Skipping other keys because we got error. */ + return; + } + + if (resolve->id != keys->id) { + /* We are only interested in keys for the given id */ + return; + } + + resolve->err = conflict_check_and_replace(resolve->id, keys); +} + +int bt_id_resolving_list_check_and_update(uint8_t id, const bt_addr_le_t *peer) +{ + int err; + + if (peer == NULL) { + struct bt_id_resolve resolve = { + .id = id, + }; + + LOG_DBG("Updating resolving list for id %u without peer address", id); + + bt_keys_foreach_type(BT_KEYS_IRK, check_and_add_keys_for_id, &resolve); + err = resolve.err; + } else { + struct bt_keys *keys; + + LOG_DBG("Updating resolving list for id %u addr %s", id, bt_addr_le_str(peer)); + + keys = bt_keys_get_addr(id, peer); + if (!keys) { + LOG_DBG("No keys found for id %u addr %s", id, bt_addr_le_str(peer)); + return -ENOENT; + } + + err = conflict_check_and_replace(id, keys); + } + + if (err) { + LOG_ERR("Failed to update resolving list for id %u addr %s (err %d)", id, + peer ? bt_addr_le_str(peer) : "NULL", err); + return err; + } + + return err; +} #endif /* defined(CONFIG_BT_SMP) */ void bt_id_get(bt_addr_le_t *addrs, size_t *count) diff --git a/subsys/bluetooth/host/id.h b/subsys/bluetooth/host/id.h index 8824d3bb496b..cd66784a5037 100644 --- a/subsys/bluetooth/host/id.h +++ b/subsys/bluetooth/host/id.h @@ -60,3 +60,26 @@ void bt_id_pending_keys_update(void); void bt_id_pending_keys_update_set(struct bt_keys *keys, uint8_t flag); void bt_id_adv_limited_stopped(struct bt_le_ext_adv *adv); + +/** + * @brief Check and update the resolving list for a given identity. + * + * This function checks if the resolving list contains the keys for the given + * identity and peer address. If the keys are not present, it adds them to the + * resolving list. If the keys are present, it checks for conflicts with + * existing keys in the resolving list. If a conflict is found, it replaces + * the conflicting key with the new key. + * + * If the peer address is NULL, it updates the resolving list for all keys that belong to the given + * identity. + * + * If for any of the keys belonging to the given identity a conflict is found and the advertiser for + * that key is enabled, the function returns an error. + * + * @param id The identity ID to check and update. + * @param peer The peer address to check against the resolving list. + * + * @return 0 on success, or a negative error code on failure. + * @return -EPERM if a conflict is found and the advertiser for the conflicting key is enabled. + */ +int bt_id_resolving_list_check_and_update(uint8_t id, const bt_addr_le_t *peer); diff --git a/subsys/bluetooth/host/keys.c b/subsys/bluetooth/host/keys.c index 0ab157599408..4707a2e0fe23 100644 --- a/subsys/bluetooth/host/keys.c +++ b/subsys/bluetooth/host/keys.c @@ -310,16 +310,57 @@ void bt_keys_add_type(struct bt_keys *keys, enum bt_keys_type type) keys->keys |= type; } +static void add_id_cb(struct k_work *work) +{ + bt_id_pending_keys_update(); +} + +static K_WORK_DEFINE(add_id_work, add_id_cb); + void bt_keys_clear(struct bt_keys *keys) { + struct bt_keys *conflict = NULL; + __ASSERT_NO_MSG(keys != NULL); LOG_DBG("%s (keys 0x%04x)", bt_addr_le_str(&keys->addr), keys->keys); + if (IS_ENABLED(CONFIG_BT_ID_AUTO_SWAP_MATCHING_BONDS) && + (keys->flags & BT_KEYS_ID_CONFLICT) != 0) { + /* We need to check how many conflicting keys left. If there is only one conflicting + * key left, we can remove the BT_KEYS_ID_CONFLICT flag from it so that Host don't + * need to check and update the Resolving List whenever this is needed. The key + * should be re-added to the Resolving List. + */ + bool found_multiple; + + found_multiple = bt_id_find_conflict_multiple(keys, &conflict); + if (conflict) { + if (found_multiple || (conflict->state & BT_KEYS_ID_ADDED) != 0) { + /* If we found multiple conflicting keys or the conflicting key + * is already added to the ID list, we don't need to clear the + * conflict flag for it and re-add it to the Resolving List. + */ + conflict = NULL; + } else { + /* Clear the conflict flag for the conflicting key */ + conflict->flags &= ~BT_KEYS_ID_CONFLICT; + } + } + } + if (keys->state & BT_KEYS_ID_ADDED) { bt_id_del(keys); } + if (conflict) { + /* Re-add the conflicting key to the Resolving List if it was the last conflicting + * key. + */ + bt_id_pending_keys_update_set(conflict, BT_KEYS_ID_PENDING_ADD); + k_work_submit(&add_id_work); + } + if (IS_ENABLED(CONFIG_BT_SETTINGS)) { /* Delete stored keys from flash */ bt_settings_delete_keys(keys->id, &keys->addr); @@ -347,6 +388,28 @@ int bt_keys_store(struct bt_keys *keys) return 0; } +static void check_and_set_id_conflict_flag(struct bt_keys *keys) +{ + struct bt_keys *conflict; + + if (!IS_ENABLED(CONFIG_BT_ID_AUTO_SWAP_MATCHING_BONDS)) { + /* If auto-swap is not enabled, we don't need to check for conflicts */ + return; + } + + /* Use bt_id_find_conflict() to check if there are any conflicting keys for the given keys. + * If there is at least one, set the BT_KEYS_ID_CONFLICT flag for both the keys and the + * conflicting key. + */ + conflict = bt_id_find_conflict(keys, true); + if (conflict != NULL) { + LOG_DBG("Found conflicting key %p.", conflict); + + keys->flags |= BT_KEYS_ID_CONFLICT; + conflict->flags |= BT_KEYS_ID_CONFLICT; + } +} + static int keys_set(const char *name, size_t len_rd, settings_read_cb read_cb, void *cb_arg) { @@ -439,6 +502,8 @@ static int keys_set(const char *name, size_t len_rd, settings_read_cb read_cb, keys->flags &= ~BT_KEYS_AUTHENTICATED; } + check_and_set_id_conflict_flag(keys); + LOG_DBG("Successfully restored keys for %s", bt_addr_le_str(&addr)); #if defined(CONFIG_BT_KEYS_OVERWRITE_OLDEST) if (aging_counter_val < keys->aging_counter) { @@ -448,17 +513,17 @@ static int keys_set(const char *name, size_t len_rd, settings_read_cb read_cb, return 0; } -static void add_id_cb(struct k_work *work) -{ - bt_id_pending_keys_update(); -} - -static K_WORK_DEFINE(add_id_work, add_id_cb); - static void id_add(struct bt_keys *keys, void *user_data) { __ASSERT_NO_MSG(keys != NULL); + if (keys->flags & BT_KEYS_ID_CONFLICT) { + /* If the keys have the conflict flag set, we don't want to add them to the ID list, + * as this will cause issues with resolving list. + */ + return; + } + bt_id_pending_keys_update_set(keys, BT_KEYS_ID_PENDING_ADD); k_work_submit(&add_id_work); } diff --git a/subsys/bluetooth/host/keys.h b/subsys/bluetooth/host/keys.h index ab83aff8ebf0..90c0c92e9de0 100644 --- a/subsys/bluetooth/host/keys.h +++ b/subsys/bluetooth/host/keys.h @@ -45,6 +45,12 @@ enum { /* Bit 2 and 3 might accidentally exist in old stored keys */ BT_KEYS_SC = BIT(4), BT_KEYS_OOB = BIT(5), + /** Indicates that the keys are in conflict with existing keys. + * + * This is used to indicate that the keys being added conflict with + * existing keys from different identity. + */ + BT_KEYS_ID_CONFLICT = BIT(6), }; struct bt_ltk { diff --git a/subsys/bluetooth/host/smp.c b/subsys/bluetooth/host/smp.c index 1a5592d1d6c2..11fa7a4361f3 100644 --- a/subsys/bluetooth/host/smp.c +++ b/subsys/bluetooth/host/smp.c @@ -924,7 +924,7 @@ static void smp_br_id_add_replace(struct bt_keys *keys) bt_id_del(keys); } - conflict = bt_id_find_conflict(keys); + conflict = bt_id_find_conflict(keys, false); if (conflict != NULL) { int err; @@ -934,7 +934,7 @@ static void smp_br_id_add_replace(struct bt_keys *keys) __ASSERT_NO_MSG(!err); } - __ASSERT_NO_MSG(!bt_id_find_conflict(keys)); + __ASSERT_NO_MSG(!bt_id_find_conflict(keys, false)); bt_id_add(keys); } @@ -4135,16 +4135,24 @@ static uint8_t smp_id_add_replace(struct bt_smp *smp, struct bt_keys *new_bond) */ __ASSERT_NO_MSG(!(smp->remote_dist & BT_SMP_DIST_ID_KEY)); - conflict = bt_id_find_conflict(new_bond); + conflict = bt_id_find_conflict(new_bond, IS_ENABLED(CONFIG_BT_ID_AUTO_SWAP_MATCHING_BONDS)); if (conflict) { LOG_DBG("New bond conflicts with a bond on id %d.", conflict->id); } - if (conflict && !IS_ENABLED(CONFIG_BT_ID_UNPAIR_MATCHING_BONDS)) { + if (conflict && !IS_ENABLED(CONFIG_BT_ID_AUTO_SWAP_MATCHING_BONDS) && + !IS_ENABLED(CONFIG_BT_ID_UNPAIR_MATCHING_BONDS)) { LOG_WRN("Refusing new pairing. The old bond must be unpaired first."); return BT_SMP_ERR_AUTH_REQUIREMENTS; } + if (conflict && IS_ENABLED(CONFIG_BT_ID_AUTO_SWAP_MATCHING_BONDS)) { + LOG_WRN("Conflict detected with %p. Don't add key to Resolve List.", conflict); + new_bond->flags |= BT_KEYS_ID_CONFLICT; + conflict->flags |= BT_KEYS_ID_CONFLICT; + return 0; + } + if (conflict && IS_ENABLED(CONFIG_BT_ID_UNPAIR_MATCHING_BONDS)) { bool trust_ok; int unpair_err; @@ -4161,7 +4169,7 @@ static uint8_t smp_id_add_replace(struct bt_smp *smp, struct bt_keys *new_bond) __ASSERT_NO_MSG(!unpair_err); } - __ASSERT_NO_MSG(!bt_id_find_conflict(new_bond)); + __ASSERT_NO_MSG(!bt_id_find_conflict(new_bond, false)); bt_id_add(new_bond); return 0; } diff --git a/tests/bluetooth/host/id/mocks/adv.c b/tests/bluetooth/host/id/mocks/adv.c index 2c2d4f3f3c7a..a22123dea3da 100644 --- a/tests/bluetooth/host/id/mocks/adv.c +++ b/tests/bluetooth/host/id/mocks/adv.c @@ -15,3 +15,4 @@ DEFINE_FAKE_VALUE_FUNC(int, bt_le_adv_set_enable_legacy, struct bt_le_ext_adv *, DEFINE_FAKE_VALUE_FUNC(int, bt_le_adv_set_enable_ext, struct bt_le_ext_adv *, bool, const struct bt_le_ext_adv_start_param *); DEFINE_FAKE_VOID_FUNC(bt_le_ext_adv_foreach, bt_le_ext_adv_foreach_cb, void *); +DEFINE_FAKE_VALUE_FUNC(struct bt_le_ext_adv *, bt_adv_lookup_by_id, uint8_t); diff --git a/tests/bluetooth/host/id/mocks/adv.h b/tests/bluetooth/host/id/mocks/adv.h index bfb744001596..1602ddf47185 100644 --- a/tests/bluetooth/host/id/mocks/adv.h +++ b/tests/bluetooth/host/id/mocks/adv.h @@ -18,7 +18,8 @@ typedef void (*bt_le_ext_adv_foreach_cb)(struct bt_le_ext_adv *adv, void *data); FAKE(bt_le_adv_lookup_legacy) \ FAKE(bt_le_ext_adv_get_index) \ FAKE(bt_le_adv_set_enable_ext) \ - FAKE(bt_le_ext_adv_foreach) + FAKE(bt_le_ext_adv_foreach) \ + FAKE(bt_adv_lookup_by_id) DECLARE_FAKE_VALUE_FUNC(int, bt_le_adv_set_enable, struct bt_le_ext_adv *, bool); DECLARE_FAKE_VALUE_FUNC(struct bt_le_ext_adv *, bt_le_adv_lookup_legacy); @@ -27,3 +28,4 @@ DECLARE_FAKE_VALUE_FUNC(int, bt_le_adv_set_enable_legacy, struct bt_le_ext_adv * DECLARE_FAKE_VALUE_FUNC(int, bt_le_adv_set_enable_ext, struct bt_le_ext_adv *, bool, const struct bt_le_ext_adv_start_param *); DECLARE_FAKE_VOID_FUNC(bt_le_ext_adv_foreach, bt_le_ext_adv_foreach_cb, void *); +DECLARE_FAKE_VALUE_FUNC(struct bt_le_ext_adv *, bt_adv_lookup_by_id, uint8_t); diff --git a/tests/bluetooth/host/id/mocks/keys.c b/tests/bluetooth/host/id/mocks/keys.c index f885ab875c0f..61f73569c469 100644 --- a/tests/bluetooth/host/id/mocks/keys.c +++ b/tests/bluetooth/host/id/mocks/keys.c @@ -10,3 +10,4 @@ DEFINE_FAKE_VALUE_FUNC(struct bt_keys *, bt_keys_find_irk, uint8_t, const bt_addr_le_t *); DEFINE_FAKE_VOID_FUNC(bt_keys_foreach_type, enum bt_keys_type, bt_keys_foreach_type_cb, void *); +DEFINE_FAKE_VALUE_FUNC(struct bt_keys *, bt_keys_get_addr, uint8_t, const bt_addr_le_t *); diff --git a/tests/bluetooth/host/id/mocks/keys.h b/tests/bluetooth/host/id/mocks/keys.h index b6901e315ab9..1912472b78de 100644 --- a/tests/bluetooth/host/id/mocks/keys.h +++ b/tests/bluetooth/host/id/mocks/keys.h @@ -15,7 +15,9 @@ typedef void (*bt_keys_foreach_type_cb)(struct bt_keys *keys, void *data); /* List of fakes used by this unit tester */ #define KEYS_FFF_FAKES_LIST(FAKE) \ FAKE(bt_keys_find_irk) \ - FAKE(bt_keys_foreach_type) + FAKE(bt_keys_foreach_type) \ + FAKE(bt_keys_get_addr) DECLARE_FAKE_VALUE_FUNC(struct bt_keys *, bt_keys_find_irk, uint8_t, const bt_addr_le_t *); DECLARE_FAKE_VOID_FUNC(bt_keys_foreach_type, enum bt_keys_type, bt_keys_foreach_type_cb, void *); +DECLARE_FAKE_VALUE_FUNC(struct bt_keys *, bt_keys_get_addr, uint8_t, const bt_addr_le_t *);