This is an automated email from the ASF dual-hosted git repository.

sjanc pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-nimble.git

commit 6f84e638150c55bf8b9819d30c036b5b300f7c91
Author: Szymon Czapracki <[email protected]>
AuthorDate: Tue Mar 31 18:22:36 2026 +0200

    nimble/host: Implement NRPA rotation
    
    New functionality for NRPA rotation.
    NRPA will use RPA_TIMEOUT as refresh time.
    Only extended advertising set is affected by this change.
---
 nimble/host/src/ble_gap.c | 158 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 158 insertions(+)

diff --git a/nimble/host/src/ble_gap.c b/nimble/host/src/ble_gap.c
index 9588a14e9..01f8e20ac 100644
--- a/nimble/host/src/ble_gap.c
+++ b/nimble/host/src/ble_gap.c
@@ -186,11 +186,16 @@ struct ble_gap_slave_state {
     unsigned int high_duty_directed:1;
     unsigned int legacy_pdu:1;
     unsigned int rnd_addr_set:1;
+    unsigned int nrpa_exp_set : 1;
 #if MYNEWT_VAL(BLE_PERIODIC_ADV)
     unsigned int periodic_configured:1;
     uint8_t      periodic_op;
 #endif
     uint8_t rnd_addr[6];
+    ble_npl_time_t nrpa_exp_os_ticks;
+    ble_npl_time_t adv_start_time;
+    uint16_t adv_duration;
+    uint8_t adv_max_events;
 #else
 /* timer is used only with legacy advertising */
     unsigned int exp_set:1;
@@ -202,10 +207,141 @@ struct ble_gap_slave_state {
 };
 
 static bssnz_t struct ble_gap_slave_state ble_gap_slave[BLE_ADV_INSTANCES];
+#if MYNEWT_VAL(BLE_EXT_ADV)
+static int ble_gap_ext_adv_set_addr_no_lock(uint8_t instance, const uint8_t 
*addr);
+static int ble_gap_ext_adv_stop_no_lock(uint8_t instance);
+int ble_gap_ext_adv_start(uint8_t instance, int duration, int max_events);
+#endif
 
 #if NIMBLE_BLE_ADVERTISE
 #if MYNEWT_VAL(BLE_EXT_ADV)
 static bool ext_adv_legacy_configured = false;
+
+static bool
+ble_gap_ext_adv_rnd_addr_is_nrpa(const uint8_t *addr)
+{
+    return (addr[5] & 0xc0) == 0;
+}
+
+static uint16_t
+ble_gap_ext_adv_remaining_duration(uint8_t instance)
+{
+    ble_npl_time_t elapsed_ticks;
+    uint32_t elapsed_ms;
+    uint32_t elapsed_units;
+
+    if (ble_gap_slave[instance].adv_duration == 0) {
+        return 0;
+    }
+
+    elapsed_ticks = ble_npl_time_get() - 
ble_gap_slave[instance].adv_start_time;
+    elapsed_ms = ble_npl_time_ticks_to_ms32(elapsed_ticks);
+    elapsed_units = elapsed_ms / 10;
+
+    if (elapsed_units >= ble_gap_slave[instance].adv_duration) {
+        return 1;
+    }
+
+    return ble_gap_slave[instance].adv_duration - elapsed_units;
+}
+
+static int
+ble_gap_ext_adv_nrpa_rotate(uint8_t instance, const uint8_t *addr)
+{
+    uint16_t duration;
+    uint8_t max_events;
+    int rc;
+
+    duration = ble_gap_ext_adv_remaining_duration(instance);
+    max_events = ble_gap_slave[instance].adv_max_events;
+
+    rc = ble_gap_ext_adv_stop_no_lock(instance);
+    if (rc != 0) {
+        return rc;
+    }
+
+    rc = ble_gap_ext_adv_set_addr_no_lock(instance, addr);
+    if (rc != 0) {
+        return rc;
+    }
+
+    rc = ble_gap_ext_adv_start(instance, duration, max_events);
+    if (rc != 0) {
+        return rc;
+    }
+
+    return 0;
+}
+
+static void
+ble_gap_ext_adv_nrpa_set_exp(uint8_t instance)
+{
+    ble_npl_time_t timeout_ticks;
+    uint32_t timeout_ms;
+    int rc;
+
+    timeout_ms = MYNEWT_VAL(BLE_RPA_TIMEOUT) * 1000UL;
+
+    rc = ble_npl_time_ms_to_ticks(timeout_ms, &timeout_ticks);
+    BLE_HS_DBG_ASSERT_EVAL(rc == 0);
+
+    ble_gap_slave[instance].nrpa_exp_os_ticks = ble_npl_time_get() + 
timeout_ticks;
+    ble_gap_slave[instance].nrpa_exp_set = 1;
+    ble_hs_timer_resched();
+}
+
+static void
+ble_gap_ext_adv_nrpa_clear_exp(uint8_t instance)
+{
+    ble_gap_slave[instance].nrpa_exp_set = 0;
+    ble_hs_timer_resched();
+}
+
+static uint32_t
+ble_gap_ext_adv_nrpa_timer(void)
+{
+    ble_npl_stime_t ticks;
+    uint32_t min_ticks;
+    ble_addr_t addr;
+    int rc;
+    int i;
+
+    min_ticks = BLE_HS_FOREVER;
+
+    for (i = 0; i < BLE_ADV_INSTANCES; i++) {
+        if (ble_gap_slave[i].op != BLE_GAP_OP_S_ADV ||
+            !ble_gap_slave[i].rnd_addr_set || !ble_gap_slave[i].nrpa_exp_set ||
+            !ble_gap_ext_adv_rnd_addr_is_nrpa(ble_gap_slave[i].rnd_addr)) {
+            continue;
+        }
+
+        ticks = ble_gap_slave[i].nrpa_exp_os_ticks - ble_npl_time_get();
+        if (ticks > 0) {
+            min_ticks = min(min_ticks, ticks);
+            continue;
+        }
+
+        rc = ble_hs_id_gen_rnd(1, &addr);
+        if (rc != 0) {
+            min_ticks = min(min_ticks, ble_npl_time_ms_to_ticks32(
+                                           BLE_GAP_CANCEL_RETRY_TIMEOUT_MS));
+            continue;
+        }
+
+        rc = ble_gap_ext_adv_nrpa_rotate(i, addr.val);
+        if (rc != 0) {
+            min_ticks = min(min_ticks, ble_npl_time_ms_to_ticks32(
+                                           BLE_GAP_CANCEL_RETRY_TIMEOUT_MS));
+            continue;
+        }
+
+        ble_gap_ext_adv_nrpa_set_exp(i);
+        ticks = ble_gap_slave[i].nrpa_exp_os_ticks - ble_npl_time_get();
+        min_ticks = min(min_ticks, ticks);
+    }
+
+    return min_ticks;
+}
 #endif
 #endif
 
@@ -2388,6 +2524,10 @@ ble_gap_timer(void)
     min_ticks = min(min_ticks, ble_gap_slave_timer());
 #endif
 
+#if NIMBLE_BLE_ADVERTISE && MYNEWT_VAL(BLE_EXT_ADV)
+    min_ticks = min(min_ticks, ble_gap_ext_adv_nrpa_timer());
+#endif
+
     return min_ticks;
 }
 
@@ -3430,6 +3570,13 @@ ble_gap_ext_adv_set_addr_no_lock(uint8_t instance, const 
uint8_t *addr)
     ble_gap_slave[instance].rnd_addr_set = 1;
     memcpy(ble_gap_slave[instance].rnd_addr, addr, 6);
 
+    if (ble_gap_ext_adv_rnd_addr_is_nrpa(addr) &&
+        ble_gap_slave[instance].op == BLE_GAP_OP_S_ADV) {
+        ble_gap_ext_adv_nrpa_set_exp(instance);
+    } else if (!ble_gap_ext_adv_rnd_addr_is_nrpa(addr)) {
+        ble_gap_ext_adv_nrpa_clear_exp(instance);
+    }
+
     return 0;
 }
 
@@ -3551,8 +3698,18 @@ ble_gap_ext_adv_start(uint8_t instance, int duration, 
int max_events)
     }
 
     ble_gap_slave[instance].op = BLE_GAP_OP_S_ADV;
+    ble_gap_slave[instance].adv_start_time = ble_npl_time_get();
+    ble_gap_slave[instance].adv_duration = duration;
+    ble_gap_slave[instance].adv_max_events = max_events;
 
+    if (ble_gap_slave[instance].rnd_addr_set &&
+        ble_gap_ext_adv_rnd_addr_is_nrpa(ble_gap_slave[instance].rnd_addr)) {
+        ble_gap_ext_adv_nrpa_set_exp(instance);
+    } else {
+        ble_gap_ext_adv_nrpa_clear_exp(instance);
+    }
     ble_hs_unlock();
+
     return 0;
 }
 
@@ -3587,6 +3744,7 @@ ble_gap_ext_adv_stop_no_lock(uint8_t instance)
     }
 
     ble_gap_slave[instance].op = BLE_GAP_OP_NULL;
+    ble_gap_ext_adv_nrpa_clear_exp(instance);
 
     if (!active) {
         return BLE_HS_EALREADY;

Reply via email to