Diff between 8648ed970e283f7aa1efc081de72a8cbac7e1ae1 and d9294d644930c88c875b35b9efa10beb0854c13b

Changed Files

File Additions Deletions Status
src/adapter.c +11 -3 modified
src/device.c +38 -27 modified
src/device.h +1 -0 modified

Full Patch

diff --git a/src/adapter.c b/src/adapter.c
index bb2c017..146d141 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -5662,7 +5662,7 @@ static void new_irk_callback(uint16_t index, uint16_t length,
 	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];
 
@@ -5676,12 +5676,17 @@ static void new_irk_callback(uint16_t index, uint16_t length,
 
 	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);
@@ -5690,6 +5695,9 @@ static void new_irk_callback(uint16_t index, uint16_t length,
 
 	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
@@ -274,37 +274,13 @@ static GSList *find_service_with_state(GSList *list,
 
 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)
@@ -2477,6 +2453,41 @@ void device_update_last_seen(struct btd_device *device, uint8_t bdaddr_type)
 		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
@@ -42,6 +42,7 @@ void device_update_addr(struct btd_device *device, const bdaddr_t *bdaddr,
 							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);