Skip to content

Commit 647f0e1

Browse files
PavelVPVjukkar
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. Signed-off-by: Pavel Vasilyev <[email protected]> (cherry picked from commit 1890dba)
1 parent caf402b commit 647f0e1

File tree

14 files changed

+427
-30
lines changed

14 files changed

+427
-30
lines changed

include/zephyr/bluetooth/bluetooth.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1496,6 +1496,10 @@ struct bt_le_per_adv_param {
14961496
* This error code is only guaranteed when using Zephyr
14971497
* controller, for other controllers code returned in
14981498
* this case may be -EIO.
1499+
* @return -EPERM When @kconfig{CONFIG_BT_PRIVACY} and
1500+
* @kconfig{CONFIG_BT_ID_AUTO_SWAP_MATCHING_BONDS} are enabled and connectable
1501+
* advertising is requested, and the given local identity has a conflicting
1502+
* key with another local identity for which advertising is already started.
14991503
*/
15001504
int bt_le_adv_start(const struct bt_le_adv_param *param,
15011505
const struct bt_data *ad, size_t ad_len,
@@ -1623,6 +1627,12 @@ struct bt_le_ext_adv_start_param {
16231627
*
16241628
* @param adv Advertising set object.
16251629
* @param param Advertise start parameters.
1630+
*
1631+
* @return Zero on success or (negative) error code otherwise.
1632+
* @return -EPERM When @kconfig{CONFIG_BT_PRIVACY} and
1633+
* @kconfig{CONFIG_BT_ID_AUTO_SWAP_MATCHING_BONDS} are enabled and connectable
1634+
* advertising is requested, and the given local identity has a conflicting
1635+
* key with another local identity for which advertising is already started.
16261636
*/
16271637
int bt_le_ext_adv_start(struct bt_le_ext_adv *adv,
16281638
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
@@ -630,6 +630,24 @@ config BT_ID_UNPAIR_MATCHING_BONDS
630630
link-layer. The Host does not have control over this acknowledgment,
631631
and the order of distribution is fixed by the specification.
632632

633+
config BT_ID_AUTO_SWAP_MATCHING_BONDS
634+
bool "Automatically swap conflicting entries in the Resolving List"
635+
depends on !BT_ID_UNPAIR_MATCHING_BONDS
636+
depends on BT_PRIVACY && BT_PERIPHERAL && !BT_CENTRAL
637+
help
638+
If this option is enabled, the Host will not add a new bond with
639+
the same peer address (or IRK) to the Resolving List if there is
640+
already a bond with the same peer address (or IRK) on another local
641+
identity.
642+
643+
In case of Peripheral, the Host will swap the existing entry in the
644+
Resolving List with the new one, so that the new bond will be used for
645+
address resolution for the new local identity if the device starts
646+
advertising with the new local identity.
647+
648+
Important: this option is supported exclusively in the Peripheral
649+
role. Excluding the Central role.
650+
633651
config BT_ID_ALLOW_UNAUTH_OVERWRITE
634652
bool "Allow unauthenticated pairing with same peer with other local identity"
635653
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
@@ -272,6 +272,25 @@ struct bt_le_ext_adv *bt_hci_adv_lookup_handle(uint8_t handle)
272272
#endif /* CONFIG_BT_BROADCASTER */
273273
#endif /* defined(CONFIG_BT_EXT_ADV) */
274274

275+
struct bt_le_ext_adv *bt_adv_lookup_by_id(uint8_t id)
276+
{
277+
#if defined(CONFIG_BT_EXT_ADV)
278+
for (size_t i = 0; i < ARRAY_SIZE(adv_pool); i++) {
279+
if (atomic_test_bit(adv_pool[i].flags, BT_ADV_CREATED) &&
280+
adv_pool[i].id == id) {
281+
return &adv_pool[i];
282+
}
283+
}
284+
#else
285+
if (atomic_test_bit(bt_dev.adv.flags, BT_ADV_CREATED) && bt_dev.adv.id == id) {
286+
return &bt_dev.adv;
287+
}
288+
#endif
289+
290+
return NULL;
291+
}
292+
293+
275294
void bt_le_ext_adv_foreach(void (*func)(struct bt_le_ext_adv *adv, void *data),
276295
void *data)
277296
{
@@ -1021,6 +1040,14 @@ int bt_le_adv_start_legacy(struct bt_le_ext_adv *adv,
10211040
adv->id = param->id;
10221041
bt_dev.adv_conn_id = adv->id;
10231042

1043+
if (IS_ENABLED(CONFIG_BT_ID_AUTO_SWAP_MATCHING_BONDS)) {
1044+
err = bt_id_resolving_list_check_and_update(adv->id, param->peer);
1045+
if (err) {
1046+
LOG_ERR("Failed to check and update resolving list: %d", err);
1047+
return err;
1048+
}
1049+
}
1050+
10241051
err = bt_id_set_adv_own_addr(adv, param->options, dir_adv,
10251052
&set_param.own_addr_type);
10261053
if (err) {
@@ -1336,6 +1363,15 @@ int bt_le_adv_start_ext(struct bt_le_ext_adv *adv,
13361363
}
13371364

13381365
adv->id = param->id;
1366+
1367+
if (IS_ENABLED(CONFIG_BT_ID_AUTO_SWAP_MATCHING_BONDS)) {
1368+
err = bt_id_resolving_list_check_and_update(adv->id, param->peer);
1369+
if (err) {
1370+
LOG_ERR("Failed to check and update resolving list: %d", err);
1371+
return err;
1372+
}
1373+
}
1374+
13391375
err = le_ext_adv_param_set(adv, param, sd != NULL);
13401376
if (err) {
13411377
return err;
@@ -1724,6 +1760,22 @@ int bt_le_ext_adv_start(struct bt_le_ext_adv *adv,
17241760
return -EALREADY;
17251761
}
17261762

1763+
if (IS_ENABLED(CONFIG_BT_ID_AUTO_SWAP_MATCHING_BONDS)) {
1764+
const bt_addr_le_t *peer;
1765+
1766+
if (bt_addr_le_eq(&adv->target_addr, BT_ADDR_LE_ANY)) {
1767+
peer = NULL;
1768+
} else {
1769+
peer = &adv->target_addr;
1770+
}
1771+
1772+
err = bt_id_resolving_list_check_and_update(adv->id, peer);
1773+
if (err) {
1774+
LOG_ERR("Failed to check and update resolving list: %d", err);
1775+
return err;
1776+
}
1777+
}
1778+
17271779
if (IS_ENABLED(CONFIG_BT_PERIPHERAL) &&
17281780
atomic_test_bit(adv->flags, BT_ADV_CONNECTABLE)) {
17291781
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
@@ -25,3 +25,4 @@ int bt_le_adv_set_enable_ext(struct bt_le_ext_adv *adv,
2525
int bt_le_adv_set_enable_legacy(struct bt_le_ext_adv *adv, bool enable);
2626
int bt_le_lim_adv_cancel_timeout(struct bt_le_ext_adv *adv);
2727
void bt_adv_reset_adv_pool(void);
28+
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)