Skip to content

Commit c268343

Browse files
PavelVPVHaavardRei
authored andcommitted
[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 <pavel.vasilyev@nordicsemi.no> (cherry picked from commit 8e030ea) (cherry picked from commit 72becd4) (cherry picked from commit 4994883)
1 parent aac20e6 commit c268343

File tree

14 files changed

+427
-32
lines changed

14 files changed

+427
-32
lines changed

include/zephyr/bluetooth/bluetooth.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1295,6 +1295,10 @@ struct bt_le_per_adv_param {
12951295
* This error code is only guaranteed when using Zephyr
12961296
* controller, for other controllers code returned in
12971297
* this case may be -EIO.
1298+
* @return -EPERM When @kconfig{CONFIG_BT_PRIVACY} and
1299+
* @kconfig{CONFIG_BT_ID_AUTO_SWAP_MATCHING_BONDS} are enabled and connectable
1300+
* advertising is requested, and the given local identity has a conflicting
1301+
* key with another local identity for which advertising is already started.
12981302
*/
12991303
int bt_le_adv_start(const struct bt_le_adv_param *param,
13001304
const struct bt_data *ad, size_t ad_len,
@@ -1422,6 +1426,12 @@ struct bt_le_ext_adv_start_param {
14221426
*
14231427
* @param adv Advertising set object.
14241428
* @param param Advertise start parameters.
1429+
*
1430+
* @return Zero on success or (negative) error code otherwise.
1431+
* @return -EPERM When @kconfig{CONFIG_BT_PRIVACY} and
1432+
* @kconfig{CONFIG_BT_ID_AUTO_SWAP_MATCHING_BONDS} are enabled and connectable
1433+
* advertising is requested, and the given local identity has a conflicting
1434+
* key with another local identity for which advertising is already started.
14251435
*/
14261436
int bt_le_ext_adv_start(struct bt_le_ext_adv *adv,
14271437
const struct bt_le_ext_adv_start_param *param);

subsys/bluetooth/host/Kconfig

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -659,6 +659,24 @@ config BT_ID_UNPAIR_MATCHING_BONDS
659659
link-layer. The Host does not have control over this acknowledgment,
660660
and the order of distribution is fixed by the specification.
661661

662+
config BT_ID_AUTO_SWAP_MATCHING_BONDS
663+
bool "Automatically swap conflicting entries in the Resolving List"
664+
depends on !BT_ID_UNPAIR_MATCHING_BONDS
665+
depends on BT_SMP && BT_PERIPHERAL && !BT_CENTRAL
666+
help
667+
If this option is enabled, the Host will not add a new bond with
668+
the same peer address (or IRK) to the Resolving List if there is
669+
already a bond with the same peer address (or IRK) on another local
670+
identity.
671+
672+
In case of Peripheral, the Host will swap the existing entry in the
673+
Resolving List with the new one, so that the new bond will be used for
674+
address resolution for the new local identity if the device starts
675+
advertising with the new local identity.
676+
677+
Important: this option is supported exclusively in the Peripheral
678+
role. Excluding the Central role.
679+
662680
config BT_ID_ALLOW_UNAUTH_OVERWRITE
663681
bool "Allow unauthenticated pairing with same peer with other local identity"
664682
depends on !BT_SMP_ALLOW_UNAUTH_OVERWRITE

subsys/bluetooth/host/adv.c

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,25 @@ struct bt_le_ext_adv *bt_hci_adv_lookup_handle(uint8_t handle)
234234
#endif /* CONFIG_BT_BROADCASTER */
235235
#endif /* defined(CONFIG_BT_EXT_ADV) */
236236

237+
struct bt_le_ext_adv *bt_adv_lookup_by_id(uint8_t id)
238+
{
239+
#if defined(CONFIG_BT_EXT_ADV)
240+
for (size_t i = 0; i < ARRAY_SIZE(adv_pool); i++) {
241+
if (atomic_test_bit(adv_pool[i].flags, BT_ADV_CREATED) &&
242+
adv_pool[i].id == id) {
243+
return &adv_pool[i];
244+
}
245+
}
246+
#else
247+
if (atomic_test_bit(bt_dev.adv.flags, BT_ADV_CREATED) && bt_dev.adv.id == id) {
248+
return &bt_dev.adv;
249+
}
250+
#endif
251+
252+
return NULL;
253+
}
254+
255+
237256
void bt_le_ext_adv_foreach(void (*func)(struct bt_le_ext_adv *adv, void *data),
238257
void *data)
239258
{
@@ -929,6 +948,14 @@ static int adv_start_legacy(struct bt_le_ext_adv *adv,
929948
adv->id = param->id;
930949
bt_dev.adv_conn_id = adv->id;
931950

951+
if (IS_ENABLED(CONFIG_BT_ID_AUTO_SWAP_MATCHING_BONDS)) {
952+
err = bt_id_resolving_list_check_and_update(adv->id, param->peer);
953+
if (err) {
954+
LOG_ERR("Failed to check and update resolving list: %d", err);
955+
return err;
956+
}
957+
}
958+
932959
err = bt_id_set_adv_own_addr(adv, param->options, dir_adv,
933960
&set_param.own_addr_type);
934961
if (err) {
@@ -1212,6 +1239,15 @@ int bt_le_adv_start_ext(struct bt_le_ext_adv *adv,
12121239
}
12131240

12141241
adv->id = param->id;
1242+
1243+
if (IS_ENABLED(CONFIG_BT_ID_AUTO_SWAP_MATCHING_BONDS)) {
1244+
err = bt_id_resolving_list_check_and_update(adv->id, param->peer);
1245+
if (err) {
1246+
LOG_ERR("Failed to check and update resolving list: %d", err);
1247+
return err;
1248+
}
1249+
}
1250+
12151251
err = le_ext_adv_param_set(adv, param, sd != NULL);
12161252
if (err) {
12171253
return err;
@@ -1499,6 +1535,22 @@ int bt_le_ext_adv_start(struct bt_le_ext_adv *adv,
14991535
return -EALREADY;
15001536
}
15011537

1538+
if (IS_ENABLED(CONFIG_BT_ID_AUTO_SWAP_MATCHING_BONDS)) {
1539+
const bt_addr_le_t *peer;
1540+
1541+
if (bt_addr_le_eq(&adv->target_addr, BT_ADDR_LE_ANY)) {
1542+
peer = NULL;
1543+
} else {
1544+
peer = &adv->target_addr;
1545+
}
1546+
1547+
err = bt_id_resolving_list_check_and_update(adv->id, peer);
1548+
if (err) {
1549+
LOG_ERR("Failed to check and update resolving list: %d", err);
1550+
return err;
1551+
}
1552+
}
1553+
15021554
if (IS_ENABLED(CONFIG_BT_PERIPHERAL) &&
15031555
atomic_test_bit(adv->flags, BT_ADV_CONNECTABLE)) {
15041556
err = le_adv_start_add_conn(adv, &conn);

subsys/bluetooth/host/adv.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,4 @@ int bt_le_adv_set_enable_ext(struct bt_le_ext_adv *adv,
2323
int bt_le_adv_set_enable_legacy(struct bt_le_ext_adv *adv, bool enable);
2424
int bt_le_lim_adv_cancel_timeout(struct bt_le_ext_adv *adv);
2525
void bt_adv_reset_adv_pool(void);
26+
struct bt_le_ext_adv *bt_adv_lookup_by_id(uint8_t id);

subsys/bluetooth/host/hci_core.h

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -497,7 +497,28 @@ struct bt_keys;
497497
void bt_id_add(struct bt_keys *keys);
498498
void bt_id_del(struct bt_keys *keys);
499499

500-
struct bt_keys *bt_id_find_conflict(struct bt_keys *candidate);
500+
/** @brief Find a conflict in the resolving list for a candidate IRK.
501+
*
502+
* @param candidate The candidate keys to check for conflicts.
503+
* @param all If true, check all IRKs, otherwise check only added keys.
504+
*
505+
* @return The conflicting key if there is one, or NULL if no conflict was found.
506+
*/
507+
struct bt_keys *bt_id_find_conflict(struct bt_keys *candidate, bool all);
508+
509+
/** * @brief Find multiple conflicts in the resolving list for a candidate IRK.
510+
*
511+
* This function iterates over all keys (added and not added to the Resolving List). If there are
512+
* multiple conflicts, this function will return true. Otherwise, it will return false.
513+
*
514+
* If @c firt_conflict is not NULL, it will be set to the first found conflict.
515+
*
516+
* @param candidate The candidate key to check for conflicts.
517+
* @param first_conflict Pointer to store the first found conflict, if any. Can be NULL.
518+
*
519+
* @return True if there are multiple conflicts, otherwise it returns false.
520+
*/
521+
bool bt_id_find_conflict_multiple(struct bt_keys *candidate, struct bt_keys **first_conflict);
501522

502523
int bt_setup_random_id_addr(void);
503524
int bt_setup_public_id_addr(void);

0 commit comments

Comments
 (0)