* [PATCH v3 1/2] Bluetooth: forget a peer's RPA once it advertises its identity address
2026-09-08 22:29 [PATCH v3 0/2] Bluetooth: dial the address the peer is actually on air with Radek Podgorny
@ 2026-09-08 22:29 ` Radek Podgorny
2026-09-08 22:29 ` [PATCH v3 2/2] Bluetooth: put the peer's on-air address on air when we cannot resolve Radek Podgorny
2026-09-09 19:40 ` [PATCH v3 0/2] Bluetooth: dial the address the peer is actually on air with patchwork-bot+bluetooth
2 siblings, 0 replies; 4+ messages in thread
From: Radek Podgorny @ 2026-09-08 22:29 UTC (permalink / raw)
To: Marcel Holtmann, Luiz Augusto von Dentz
Cc: linux-bluetooth, linux-kernel, Luiz Augusto von Dentz, Radek Podgorny
hci_connect_le() dials the RPA cached in the peer's IRK whenever one is
set, on the assumption that a peer holding an IRK is on air with a
resolvable private address. A peer that stops using privacy breaks that
assumption: it advertises its identity address, the cached RPA keeps the
value it had before the change, and the host aims at an address the peer
has abandoned.
Nothing clears the cache. hci_find_irk_by_rpa() refreshes irk->rpa each
time an advertisement resolves, so it tracks rotation, but a peer that
stops sending RPAs stops producing the reports that would update it, and
the stale address then survives until the adapter is powered off.
On the path that creates the connection object this is currently masked:
__hci_conn_add() resolves the cached RPA back to the identity address, so
that is what goes on air. It is not masked on the reuse branch, which
copies the swapped address straight into an existing conn->dst, and the
next patch removes the conversion for the case where the controller
cannot translate an identity address, so the stale RPA would be dialled
there too.
Clear the cached RPA when the peer is seen on its identity address.
hci_find_irk_by_addr() only matches public and static random addresses,
so an unresolved RPA belonging to some other device cannot reach this
path.
Assisted-by: Claude:claude-opus-5
Signed-off-by: Radek Podgorny <radek@podgorny.cz>
---
net/bluetooth/hci_event.c | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 2f5e21ff9752..03b805207ab0 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -6311,6 +6311,15 @@ static void process_adv_report(struct hci_dev *hdev, u8 type, bdaddr_t *bdaddr,
if (irk) {
bdaddr = &irk->bdaddr;
bdaddr_type = irk->addr_type;
+ } else {
+ /* The peer is on air with its identity address, so whatever
+ * RPA is cached for it has been abandoned. Drop it, or
+ * hci_connect_le() would swap it back in and dial an address
+ * the peer no longer answers.
+ */
+ irk = hci_find_irk_by_addr(hdev, bdaddr, bdaddr_type);
+ if (irk)
+ bacpy(&irk->rpa, BDADDR_ANY);
}
bdaddr_type = ev_bdaddr_type(hdev, bdaddr_type, &bdaddr_resolved);
--
2.55.0
^ permalink raw reply [flat|nested] 4+ messages in thread* [PATCH v3 2/2] Bluetooth: put the peer's on-air address on air when we cannot resolve
2026-09-08 22:29 [PATCH v3 0/2] Bluetooth: dial the address the peer is actually on air with Radek Podgorny
2026-09-08 22:29 ` [PATCH v3 1/2] Bluetooth: forget a peer's RPA once it advertises its identity address Radek Podgorny
@ 2026-09-08 22:29 ` Radek Podgorny
2026-09-09 19:40 ` [PATCH v3 0/2] Bluetooth: dial the address the peer is actually on air with patchwork-bot+bluetooth
2 siblings, 0 replies; 4+ messages in thread
From: Radek Podgorny @ 2026-09-08 22:29 UTC (permalink / raw)
To: Marcel Holtmann, Luiz Augusto von Dentz
Cc: linux-bluetooth, linux-kernel, Luiz Augusto von Dentz, Radek Podgorny
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>
---
net/bluetooth/hci_conn.c | 13 +++++++++++++
1 file changed, 13 insertions(+)
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:
--
2.55.0
^ permalink raw reply [flat|nested] 4+ messages in thread* Re: [PATCH v3 0/2] Bluetooth: dial the address the peer is actually on air with
2026-09-08 22:29 [PATCH v3 0/2] Bluetooth: dial the address the peer is actually on air with Radek Podgorny
2026-09-08 22:29 ` [PATCH v3 1/2] Bluetooth: forget a peer's RPA once it advertises its identity address Radek Podgorny
2026-09-08 22:29 ` [PATCH v3 2/2] Bluetooth: put the peer's on-air address on air when we cannot resolve Radek Podgorny
@ 2026-09-09 19:40 ` patchwork-bot+bluetooth
2 siblings, 0 replies; 4+ messages in thread
From: patchwork-bot+bluetooth @ 2026-09-09 19:40 UTC (permalink / raw)
To: Radek Podgorny
Cc: marcel, luiz.dentz, linux-bluetooth, linux-kernel, luiz.von.dentz
Hello:
This series was applied to bluetooth/bluetooth-next.git (master)
by Luiz Augusto von Dentz <luiz.von.dentz@intel.com>:
On Wed, 09 Sep 2026 00:29:35 +0200 you wrote:
> An identity address only reaches a peer advertising an RPA if the
> controller resolves it for us; where it cannot, the host has to dial the
> peer's on-air address itself. v2 did that by keeping the RPA in conn->dst
> when the controller will not translate, which Luiz asked for and which
> holds for as long as the peer is still using that RPA.
>
> It does not hold once a peer turns privacy off. hci_connect_le() swaps in
> the cached RPA whenever the IRK has one, nothing ever clears that cache,
> and a peer that stops sending RPAs stops producing the reports that would
> refresh it. Before this series the conversion in __hci_conn_add() hid the
> problem by turning the stale RPA back into the identity address; keeping
> the RPA exposes it, and every connect attempt goes to an address the peer
> has abandoned.
>
> [...]
Here is the summary with links:
- [v3,1/2] Bluetooth: forget a peer's RPA once it advertises its identity address
https://git.kernel.org/bluetooth/bluetooth-next/c/fb3a817741b1
- [v3,2/2] Bluetooth: put the peer's on-air address on air when we cannot resolve
https://git.kernel.org/bluetooth/bluetooth-next/c/e35544d23359
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
^ permalink raw reply [flat|nested] 4+ messages in thread