From f1fb4f95f49ee4221aa8352bc94cd53f06407953 Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Wed, 1 Oct 2025 10:27:38 -0400 Subject: [PATCH] core: Fix not resolving addresses When using the likes of btd_adapter_get_device the address can sometimes be the so called RPA which needs to be resolved in order to avoid creating duplicated objects of the same device. Note that normally the RPA are resolved in the kernel but there are instances like BASS Add Source that may attempt to add a device direcly, bypassing the GAP layer. --- src/adapter.c | 4 ++-- src/device.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++++--- src/device.h | 5 +++-- 3 files changed, 55 insertions(+), 7 deletions(-) diff --git a/src/adapter.c b/src/adapter.c index 3afcb9277..1ee2f3a08 100644 --- a/src/adapter.c +++ b/src/adapter.c @@ -5091,7 +5091,7 @@ static void load_devices(struct btd_adapter *adapter) goto free; if (irk_info) - device_set_privacy(device, true); + device_set_privacy(device, true, irk_info->val); btd_device_set_temporary(device, false); adapter_add_device(adapter, device); @@ -9024,7 +9024,7 @@ static void new_irk_callback(uint16_t index, uint16_t length, return; } - device_update_addr(device, &addr->bdaddr, addr->type); + device_update_addr(device, &addr->bdaddr, addr->type, irk->val); if (duplicate) device_merge_duplicate(device, duplicate); diff --git a/src/device.c b/src/device.c index 9f0e8e673..8d74ae0ea 100644 --- a/src/device.c +++ b/src/device.c @@ -205,6 +205,7 @@ struct btd_device { bdaddr_t bdaddr; uint8_t bdaddr_type; bool privacy; + uint8_t *irk; char *path; struct btd_bearer *bredr; struct btd_bearer *le; @@ -4995,9 +4996,17 @@ void device_set_class(struct btd_device *device, uint32_t class) DEVICE_INTERFACE, "Icon"); } -void device_set_privacy(struct btd_device *device, bool value) +void device_set_privacy(struct btd_device *device, bool value, + const uint8_t *irk) { device->privacy = value; + + free(device->irk); + + if (irk) + device->irk = util_memdup(irk, 16); + else + device->irk = NULL; } bool device_get_privacy(struct btd_device *device) @@ -5009,11 +5018,11 @@ bool device_get_privacy(struct btd_device *device) } void device_update_addr(struct btd_device *device, const bdaddr_t *bdaddr, - uint8_t bdaddr_type) + uint8_t bdaddr_type, const uint8_t *irk) { bool auto_connect = device->auto_connect; - device_set_privacy(device, true); + device_set_privacy(device, true, irk); if (!bacmp(bdaddr, &device->bdaddr) && bdaddr_type == device->bdaddr_type) @@ -5347,6 +5356,39 @@ static bool addr_is_public(uint8_t addr_type) return false; } +static bool addr_is_resolvable(const bdaddr_t *bdaddr, uint8_t addr_type) +{ + if (addr_type != BDADDR_LE_RANDOM) + return false; + + switch (bdaddr->b[5] >> 6) { + case 0x01: /* Private resolvable */ + return true; + default: + return false; + } +} + +static bool device_irk_cmp(const struct btd_device *device, + const struct device_addr_type *addr) +{ + struct bt_crypto *crypto; + uint8_t hash[3]; + + if (!device->irk) + return false; + + crypto = bt_crypto_new(); + if (!crypto) + return false; + + bt_crypto_ah(crypto, device->irk, addr->bdaddr.b + 3, hash); + + bt_crypto_unref(crypto); + + return !memcmp(addr, hash, 3); +} + int device_addr_type_cmp(gconstpointer a, gconstpointer b) { const struct btd_device *dev = a; @@ -5375,8 +5417,13 @@ int device_addr_type_cmp(gconstpointer a, gconstpointer b) return -1; if (addr->bdaddr_type != dev->bdaddr_type) { + if (dev->privacy && addr_is_resolvable(&addr->bdaddr, + addr->bdaddr_type)) + return device_irk_cmp(dev, addr); + if (addr->bdaddr_type == dev->conn_bdaddr_type) return bacmp(&dev->conn_bdaddr, &addr->bdaddr); + return -1; } diff --git a/src/device.h b/src/device.h index 6fbbdb1f2..9ff9cdfef 100644 --- a/src/device.h +++ b/src/device.h @@ -29,10 +29,11 @@ bool device_is_name_resolve_allowed(struct btd_device *device); void device_name_resolve_fail(struct btd_device *device); void device_set_class(struct btd_device *device, uint32_t class); bool device_address_is_private(struct btd_device *dev); -void device_set_privacy(struct btd_device *device, bool value); +void device_set_privacy(struct btd_device *device, bool value, + const uint8_t *irk); bool device_get_privacy(struct btd_device *device); void device_update_addr(struct btd_device *device, const bdaddr_t *bdaddr, - uint8_t bdaddr_type); + uint8_t bdaddr_type, const uint8_t *irk); void device_set_bredr_support(struct btd_device *device); void device_set_le_support(struct btd_device *device, uint8_t bdaddr_type); void device_update_last_seen(struct btd_device *device, uint8_t bdaddr_type, -- 2.47.3