[PATCH 1/2] Bluetooth: record when an IRK's RPA was last seen

From: Radek Podgorny

Date: Mon Sep 07 2026 - 19:24:01 EST


hci_find_irk_by_rpa() caches the resolvable private address it just
matched in irk->rpa, but nothing records when. A cached RPA is only
useful while the peer is still using it -- RPAs rotate on the order of
15 minutes -- and without a timestamp there is no way to tell a value
seen seconds ago from one left over from hours ago.

Stamp the time in both loops, the cache hit as well as the resolve, so
the stamp tracks when the address was last seen on air rather than when
it was first resolved.

hci_add_irk() can install a live address as well: when SMP receives a
peer's IRK over a connection established to its RPA, which is the usual
way the cache is first populated, it passes that address along. Stamp
it there too, so a non-zero rpa always carries a current time; the mgmt
load path, which passes BDADDR_ANY, leaves the stamp alone, and readers
check the address before the time either way.

The store races with concurrent readers the same way the existing
bacpy() to irk->rpa does. Both are benign -- a reader either sees the
previous value or the new one -- but use WRITE_ONCE() to say so.

Assisted-by: Claude:claude-opus-5
Signed-off-by: Radek Podgorny <radek@xxxxxxxxxxx>
---
include/net/bluetooth/hci_core.h | 4 ++++
net/bluetooth/hci_core.c | 4 ++++
2 files changed, 8 insertions(+)

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index c12cd6873f65..8308ef6160d3 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -212,6 +212,10 @@ struct smp_irk {
struct list_head list;
struct rcu_head rcu;
bdaddr_t rpa;
+ /* when rpa was last seen on air; used to decide whether the peer is
+ * currently advertising an RPA or its identity address
+ */
+ unsigned long rpa_jiffies;
bdaddr_t bdaddr;
u8 addr_type;
u8 val[16];
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 66840df8c020..8ee26cb10276 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -1179,6 +1179,7 @@ struct smp_irk *hci_find_irk_by_rpa(struct hci_dev *hdev, bdaddr_t *rpa)
rcu_read_lock();
list_for_each_entry_rcu(irk, &hdev->identity_resolving_keys, list) {
if (!bacmp(&irk->rpa, rpa)) {
+ WRITE_ONCE(irk->rpa_jiffies, jiffies);
irk_to_return = irk;
goto done;
}
@@ -1187,6 +1188,7 @@ struct smp_irk *hci_find_irk_by_rpa(struct hci_dev *hdev, bdaddr_t *rpa)
list_for_each_entry_rcu(irk, &hdev->identity_resolving_keys, list) {
if (smp_irk_matches(hdev, irk->val, rpa)) {
bacpy(&irk->rpa, rpa);
+ WRITE_ONCE(irk->rpa_jiffies, jiffies);
irk_to_return = irk;
goto done;
}
@@ -1331,6 +1333,8 @@ struct smp_irk *hci_add_irk(struct hci_dev *hdev, bdaddr_t *bdaddr,

memcpy(irk->val, val, 16);
bacpy(&irk->rpa, rpa);
+ if (bacmp(&irk->rpa, BDADDR_ANY))
+ WRITE_ONCE(irk->rpa_jiffies, jiffies);

return irk;
}
--
2.55.0