device: Fix Device.Pair using wrong address type
authorCheng Jiang <quic_chejiang@quicinc.com>
Tue, 29 Oct 2024 07:58:30 +0000 (15:58 +0800)
committerWootak Jung <wootak.jung@samsung.com>
Thu, 20 Feb 2025 07:43:24 +0000 (16:43 +0900)
For a BLE-only device, if the device is already paired and the upper
layer attempts to pair it again, the bdaddr_type will be set to
BDADDR_BREDR since the LE connection is already bonded. This causes the
device to use the BR/EDR bearer, which stalls the pairing procedure and
requires waiting for the pairing timeout.

The bluetoothctl log below shows the error result:

[bluetooth]# pair ED:8E:0E:B3:85:C1
Attempting to pair with ED:8E:0E:B3:85:C1
Pairing successful
[RAPOO BleMouse]# disconnect ED:8E:0E:B3:85:C1
Attempting to disconnect from ED:8E:0E:B3:85:C1
[RAPOO BleMouse]#
[bluetooth]# devices Paired
Device ED:8E:0E:B3:85:C1 RAPOO BleMouse
[bluetooth]# scan le
SetDiscoveryFilter success
Discovery started
[CHG] Controller 8C:FD:F0:21:84:17 Discovering: yes
[CHG] Device ED:8E:0E:B3:85:C1 RSSI: -38
[bluetooth]# scan off
Discovery stopped
[bluetooth]# pair ED:8E:0E:B3:85:C1
Attempting to pair with ED:8E:0E:B3:85:C1
[bluetooth]#
Failed to pair: org.freedesktop.DBus.Error.NoReply

Signed-off-by: Anuj Jain <anuj01.jain@samsung.com>
src/device.c

index 1093e4fffa73b3c9f622a2a12789c1155fa9bc96..599146defd83a23e6f2c13c9aee1d62458f9c845 100644 (file)
@@ -3861,12 +3861,25 @@ static DBusMessage *pair_device(DBusConnection *conn, DBusMessage *msg,
        }
        bdaddr_type = device->bdaddr_type;
 #else
-       if (device->bredr_state.bonded)
+       /* Only use this selection algorithms when device is combo
+        * chip. Ohterwise, it will use the wrong bearer to establish
+        * a connection if the device is already paired, which will
+        * stall the pairing procedure. For example, for a BLE only
+        * device, if the device is already paired, and upper layer
+        * issue the pair device again, it will set bdaddr_type to
+        * BDADDR_BREDR since LE is bonded, then it goes with BR/EDR
+        * bearer.
+        */
+       if (device->bredr && device->le) {
+               if (device->bredr_state.bonded)
+                       bdaddr_type = device->bdaddr_type;
+               else if (device->le_state.bonded)
+                       bdaddr_type = BDADDR_BREDR;
+               else
+                       bdaddr_type = select_conn_bearer(device);
+       } else {
                bdaddr_type = device->bdaddr_type;
-       else if (device->le_state.bonded)
-               bdaddr_type = BDADDR_BREDR;
-       else
-               bdaddr_type = select_conn_bearer(device);
+       }
 
        state = get_state(device, bdaddr_type);