Skip to content

Commit 1890dba

Browse files
PavelVPVrlubos
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 93b8dd9)
1 parent 45023b2 commit 1890dba

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
@@ -1489,6 +1489,10 @@ struct bt_le_per_adv_param {
14891489
* This error code is only guaranteed when using Zephyr
14901490
* controller, for other controllers code returned in
14911491
* this case may be -EIO.
1492+
* @return -EPERM When @kconfig{CONFIG_BT_PRIVACY} and
1493+
* @kconfig{CONFIG_BT_ID_AUTO_SWAP_MATCHING_BONDS} are enabled and connectable
1494+
* advertising is requested, and the given local identity has a conflicting
1495+
* key with another local identity for which advertising is already started.
14921496
*/
14931497
int bt_le_adv_start(const struct bt_le_adv_param *param,
14941498
const struct bt_data *ad, size_t ad_len,
@@ -1616,6 +1620,12 @@ struct bt_le_ext_adv_start_param {
16161620
*
16171621
* @param adv Advertising set object.
16181622
* @param param Advertise start parameters.
1623+
*
1624+
* @return Zero on success or (negative) error code otherwise.
1625+
* @return -EPERM When @kconfig{CONFIG_BT_PRIVACY} and
1626+
* @kconfig{CONFIG_BT_ID_AUTO_SWAP_MATCHING_BONDS} are enabled and connectable
1627+
* advertising is requested, and the given local identity has a conflicting
1628+
* key with another local identity for which advertising is already started.
16191629
*/
16201630
int bt_le_ext_adv_start(struct bt_le_ext_adv *adv,
16211631
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;
@@ -1691,6 +1727,22 @@ int bt_le_ext_adv_start(struct bt_le_ext_adv *adv,
16911727
return -EALREADY;
16921728
}
16931729

1730+
if (IS_ENABLED(CONFIG_BT_ID_AUTO_SWAP_MATCHING_BONDS)) {
1731+
const bt_addr_le_t *peer;
1732+
1733+
if (bt_addr_le_eq(&adv->target_addr, BT_ADDR_LE_ANY)) {
1734+
peer = NULL;
1735+
} else {
1736+
peer = &adv->target_addr;
1737+
}
1738+
1739+
err = bt_id_resolving_list_check_and_update(adv->id, peer);
1740+
if (err) {
1741+
LOG_ERR("Failed to check and update resolving list: %d", err);
1742+
return err;
1743+
}
1744+
}
1745+
16941746
if (IS_ENABLED(CONFIG_BT_PERIPHERAL) &&
16951747
atomic_test_bit(adv->flags, BT_ADV_CONNECTABLE)) {
16961748
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
@@ -500,7 +500,28 @@ struct bt_keys;
500500
void bt_id_add(struct bt_keys *keys);
501501
void bt_id_del(struct bt_keys *keys);
502502

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

505526
int bt_setup_random_id_addr(void);
506527
int bt_setup_public_id_addr(void);

0 commit comments

Comments
 (0)