diff --git a/src/adapter.c b/src/adapter.c
index bb2c017..146d141 100644
--- a/src/adapter.c
+++ b/src/adapter.c
const struct mgmt_addr_info *addr = &ev->irk.addr;
const struct mgmt_irk_info *irk = &ev->irk;
struct btd_adapter *adapter = user_data;
- struct btd_device *device;
+ struct btd_device *device, *duplicate;
bool persistent;
char dst[18], rpa[18];
DBG("hci%u new IRK for %s RPA %s", adapter->dev_id, dst, rpa);
- if (bacmp(&ev->rpa, BDADDR_ANY))
+ if (bacmp(&ev->rpa, BDADDR_ANY)) {
device = btd_adapter_get_device(adapter, &ev->rpa,
BDADDR_LE_RANDOM);
- else
+ duplicate = btd_adapter_find_device(adapter, &addr->bdaddr);
+ if (duplicate == device)
+ duplicate = NULL;
+ } else {
device = btd_adapter_get_device(adapter, &addr->bdaddr,
addr->type);
+ duplicate = NULL;
+ }
if (!device) {
error("Unable to get device object for %s", dst);
device_update_addr(device, &addr->bdaddr, addr->type);
+ if (duplicate)
+ device_merge_duplicate(device, duplicate);
+
persistent = !!ev->store_hint;
if (!persistent)
return;
diff --git a/src/device.c b/src/device.c
index a73ba29..a52faea 100644
--- a/src/device.c
+++ b/src/device.c
static void update_technologies(GKeyFile *file, struct btd_device *dev)
{
- bool bredr = dev->bredr;
- bool le = dev->le;
const char *list[2];
- char **old_list;
- size_t i, len;
-
- /* It's theoretically possible that we've known the same
- * physical device by its Resolvable Private Address over LE and
- * its public address over BR/EDR, thereby creating two
- * btd_device objects which still share the same storage.
- * Therefore, once merging information into storage we need to
- * make sure that we don't clear the other supported technology.
- */
- old_list = g_key_file_get_string_list(file, "General",
- "SupportedTechnologies",
- &len, NULL);
- for (i = 0; i < len; i++) {
- if (!strcmp(old_list[i], "BR/EDR"))
- bredr = true;
- else if (!strcmp(old_list[i], "LE"))
- le = true;
- }
-
- g_strfreev(old_list);
+ size_t len = 0;
- len = 0;
-
- if (bredr)
+ if (dev->bredr)
list[len++] = "BR/EDR";
- if (le) {
+ if (dev->le) {
const char *type;
if (dev->bdaddr_type == BDADDR_LE_PUBLIC)
device->le_seen = time(NULL);
}
+/* It is possible that we have two device objects for the same device in
+ * case it has first been discovered over BR/EDR and has a private
+ * address when discovered over LE for the first time. In such a case we
+ * need to inherit critical values from the duplicate so that we don't
+ * ovewrite them when writing to storage. The next time bluetoothd
+ * starts the device will show up as a single instance.
+ */
+void device_merge_duplicate(struct btd_device *dev, struct btd_device *dup)
+{
+ GSList *l;
+
+ DBG("");
+
+ dev->bredr = dup->bredr;
+
+ dev->trusted = dup->trusted;
+ dev->blocked = dup->blocked;
+
+ for (l = dup->uuids; l; l = g_slist_next(l))
+ dev->uuids = g_slist_append(dev->uuids, g_strdup(l->data));
+
+ if (dev->name[0] == '\0')
+ strcpy(dev->name, dup->name);
+
+ if (!dev->alias)
+ dev->alias = g_strdup(dup->alias);
+
+ dev->class = dup->class;
+
+ dev->vendor_src = dup->vendor_src;
+ dev->vendor = dup->vendor;
+ dev->product = dup->product;
+ dev->version = dup->version;
+}
+
uint32_t btd_device_get_class(struct btd_device *device)
{
return device->class;
diff --git a/src/device.h b/src/device.h
index 7add017..d8e4df2 100644
--- a/src/device.h
+++ b/src/device.h
uint8_t bdaddr_type);
void device_set_bredr_support(struct btd_device *device, bool bredr);
void device_update_last_seen(struct btd_device *device, uint8_t bdaddr_type);
+void device_merge_duplicate(struct btd_device *dev, struct btd_device *dup);
uint32_t btd_device_get_class(struct btd_device *device);
uint16_t btd_device_get_vendor(struct btd_device *device);
uint16_t btd_device_get_vendor_src(struct btd_device *device);