summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRadek Podgorny <radek@podgorny.cz>2026-09-09 00:29:37 +0200
committerLuiz Augusto von Dentz <luiz.von.dentz@intel.com>2026-09-15 14:50:25 -0400
commit4914c499896121ae8b9d5b90f0abc5c8287ff396 (patch)
tree59e093b0ce32670b16621685c1e27e155f2bae24
parentd236517c264e41dc09833c708ef23bccb7a91219 (diff)
downloadlinux-next-4914c499896121ae8b9d5b90f0abc5c8287ff396.tar.gz
linux-next-4914c499896121ae8b9d5b90f0abc5c8287ff396.zip
Bluetooth: put the peer's on-air address on air when we cannot resolve
An identity address only reaches a peer that is advertising an RPA if the controller resolves it on our behalf. Where it cannot, the host has to put the peer's on-air address on air itself. hci_connect_le() still swaps the caller's identity address for the peer's cached RPA before creating the connection, but __hci_conn_add() resolves the RPA back to the identity address when it stores it, so the identity is what goes out. Storing the identity is right when the controller translates it on the way to the radio; without LL Privacy, or with this peer absent from the resolving list, nothing does. A peer advertising an RPA cannot answer its identity address, so the attempt burns a full create-connection timeout. That is not merely a slow connect: a controller without extended scanning cannot scan while it is initiating, so every dead attempt also takes the scanner off the air for the whole timeout. Measured on a CYW43438, which reports neither LL Privacy nor extended advertising (LE features 3f 00 00 08 00 00 00 00), against a peer advertising a resolvable private address the host holds the IRK for, with the connection requested on the peer's identity address: before: LE Create Connection to the identity address, public type 1.61s -> 22.07s, then LE Create Connection Cancel LE Connection Complete: Unknown Connection Identifier (0x02) after: LE Create Connection to the peer's RPA, random type LE Connection Complete: Success Advertising reports reaching the host per second, same window, same five unrelated devices on the adapter: before 1s:2 [nothing from 2s through 21s] 22s:5 23s:3 after 0s:11 1s:5 2s:2 3s:5 4s:3 5s:4 ... 21s:2 22s:1 23s:2 One dead connect costs twenty seconds of scanning for every device on the adapter, not just the one being dialled. Keep the RPA in conn->dst unless the controller will translate the identity address: address resolution enabled and the peer's identity actually programmed into the resolving list. Testing ll_privacy_capable() alone would not be enough: it reports the feature bit, not whether resolution is switched on and not whether this peer is in the list. Resolution is cleared with the other volatile flags on power-off and switched off again while suspend pauses scanning, and a peer's IRK is only programmed along the accept list path, so a direct-connect target, a peer without HCI_CONN_FLAG_ADDRESS_RESOLUTION, and one that did not fit in a full list are all absent from it. With the peer programmed, the identity address stays in conn->dst and the controller translates it: measured on an Intel controller, the host dials the identity and LE Enhanced Connection Complete reports Resolved Public with the peer's RPA in the separate peer resolvable private address field. With the peer absent from the list the same setup dials the RPA itself. Everything downstream already copes with an RPA in conn->dst: it is what every outgoing LE connection stored before 14b06c3a88f7, the connection complete event names the address that was dialled, and le_conn_complete_evt() resolves it back to the identity once the link is up. ISO links keep the unconditional conversion: they are created from an existing ACL or a periodic sync and never dial this address themselves. Keeping the RPA is only right while the peer is still using it, which is why the preceding patch drops the cached RPA as soon as the peer is seen advertising its identity address. Without that, a peer that turns privacy off would be dialled on the address it abandoned rather than the one it is answering on. Fixes: 14b06c3a88f7 ("Bluetooth: HCI: Always use the identity address when initializing a connection") Assisted-by: Claude:claude-opus-5 Assisted-by: Claude:claude-fable-5 Signed-off-by: Radek Podgorny <radek@podgorny.cz> Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
-rw-r--r--net/bluetooth/hci_conn.c13
1 files changed, 13 insertions, 0 deletions
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index 8de98af2fb58..c9466cb2c7c0 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -1023,6 +1023,19 @@ static struct hci_conn *__hci_conn_add(struct hci_dev *hdev, int type,
if (!hdev->le_mtu && hdev->acl_mtu < HCI_MIN_LE_MTU)
return ERR_PTR(-ECONNREFUSED);
irk = hci_get_irk(hdev, dst, dst_type);
+ /* An identity address only reaches a peer advertising an RPA
+ * if the controller translates it. Unless address resolution
+ * is enabled and this peer is programmed into the resolving
+ * list, keep the RPA the peer is on air with;
+ * le_conn_complete_evt() resolves it back once the link is
+ * up.
+ */
+ if (irk &&
+ (!hci_dev_test_flag(hdev, HCI_LL_RPA_RESOLUTION) ||
+ !hci_bdaddr_list_lookup_with_irk(&hdev->le_resolv_list,
+ &irk->bdaddr,
+ irk->addr_type)))
+ irk = NULL;
break;
case SCO_LINK:
case ESCO_LINK: