diff --git a/src/adapter.c b/src/adapter.c
index 3afcb92..1ee2f3a 100644
--- a/src/adapter.c
+++ b/src/adapter.c
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);
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 9f0e8e6..8d74ae0 100644
--- a/src/device.c
+++ b/src/device.c
bdaddr_t bdaddr;
uint8_t bdaddr_type;
bool privacy;
+ uint8_t *irk;
char *path;
struct btd_bearer *bredr;
struct btd_bearer *le;
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)
}
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)
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;
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 6fbbdb1..9ff9cdf 100644
--- a/src/device.h
+++ b/src/device.h
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,