autoconnect issue after power reset in RPA

Dear Nordic,

using NRF54L15-DK I am advertising BLE with RPA, hence it changes mac on every reset and and at specified interval. Now when Phone connects first time, it asks passkey to enter and gets bonded/paired successfully.
Issue is when I reset Board, Its mac changes in advertisement causes phone autoconnect  and asks passkey. i Need once it is bonded, then it must not ask for passkey even after  Power reset or reset until bond is deleted(Right now not implemented and not required). 

SDK & Toolchain version:-3.3.1

please help
Reagrds

#include <zephyr/bluetooth/gatt.h>
#include <zephyr/bluetooth/uuid.h>
#include <zephyr/sys/byteorder.h>
#include <hal/nrf_ficr.h>
#include <platform/CHIPDeviceLayer.h>
#include "lock_manager.h"
#include <zephyr/drivers/hwinfo.h>
#include <zephyr/bluetooth/addr.h>
#include <zephyr/random/random.h>
#include <zephyr/settings/settings.h>

#define CUSTOM_LOCK_SVC_UUID_VAL \
    BT_UUID_128_ENCODE(0x12345678, 0x1234, 0x5678, 0x1234, 0x56789abcdef0)

#define CUSTOM_LOCK_STATE_CHAR_VAL \
    BT_UUID_128_ENCODE(0x12345678, 0x1234, 0x5678, 0x1234, 0x56789abcdef1)

static struct bt_uuid_128 lock_service_uuid = BT_UUID_INIT_128(CUSTOM_LOCK_SVC_UUID_VAL);
static struct bt_uuid_128 lock_state_uuid = BT_UUID_INIT_128(CUSTOM_LOCK_STATE_CHAR_VAL);

// Variable to track BLE command state
static uint8_t ble_lock_state = 0;
unsigned int static_passkey = 123456; 


// Statically define the Custom Lock Service and its writeable characteristic
// Statically define the Custom Lock Service and its writeable characteristic
BT_GATT_SERVICE_DEFINE(custom_lock_svc,
    BT_GATT_PRIMARY_SERVICE(&lock_service_uuid),
    BT_GATT_CHARACTERISTIC(&lock_state_uuid.uuid,
                           BT_GATT_CHRC_WRITE | BT_GATT_CHRC_WRITE_WITHOUT_RESP,
                           BT_GATT_PERM_WRITE_AUTHEN, // <-- Changed from BT_GATT_PERM_WRITE
                           NULL, write_lock_state, &ble_lock_state)
);
static const struct bt_data ad[] = {
    BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
    BT_DATA(BT_DATA_NAME_COMPLETE, CONFIG_BT_DEVICE_NAME, sizeof(CONFIG_BT_DEVICE_NAME) - 1),
    // Advertise our custom 128-bit Lock Service UUID so it's easy to find!
    BT_DATA_BYTES(BT_DATA_UUID128_ALL, CUSTOM_LOCK_SVC_UUID_VAL),
};
// 1. Callback matching the exact signature required by bt_foreach_bond
static void accept_list_bond_cb(const struct bt_bond_info *info, void *user_data)
{
    int err = bt_le_filter_accept_list_add(&info->addr);
    if (err) {
        printk("Failed to add bond to accept list (err %d)\n", err);
    } else {
        printk("Added bonded device from Flash to Accept List\n");
    }
}
// 2. Function to load ALL stored bonds into the Filter Accept List
void populate_accept_list_from_stored_bonds(void)
{
    // Clear any stale accept list entries first
    bt_le_filter_accept_list_clear();

    // Iterate through all saved bonds and invoke the callback
    bt_foreach_bond(BT_ID_DEFAULT, accept_list_bond_cb, NULL);
}


// 3. For NEW device pairing completion during runtime
static void pairing_complete(struct bt_conn *conn, bool bonded)
{
    printk("Pairing completed. Bonded: %d\n", bonded);

    if (bonded) {
        // Extract connection peer address and add directly
        const bt_addr_le_t *peer_addr = bt_conn_get_dst(conn);
        if (peer_addr) {
            int err = bt_le_filter_accept_list_add(peer_addr);
            if (err) {
                printk("Failed to add new pair to accept list (err %d)\n", err);
            } else {
                printk("Added new device to Accept List:%d\n",peer_addr->a.val[0]);
            }
        }
    }
}
static void pairing_failed(struct bt_conn *conn,enum bt_security_err reason)
{
    printk("Pairing failed (%d)\n", reason);
}

static struct bt_conn_auth_info_cb auth_info_cb = {
    .pairing_complete = pairing_complete,
    .pairing_failed = pairing_failed,
};

static void security_changed(struct bt_conn *conn, bt_security_t level, enum bt_security_err err)
{
    char addr[BT_ADDR_LE_STR_LEN];
    bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));

    if (!err) {
        printk("Security changed for %s: level %u (Encryption Successful!)\n", addr, level);
    } else {
        printk("Security failed for %s: level %u err %d\n", addr, level, err);
        
        /* IF security fails on a re-connection, the bond keys on mobile or lock 
           are out of sync. Unbond to allow a clean repair. */
        if (err == BT_SECURITY_ERR_PIN_OR_KEY_MISSING || err == 9) {
            printk("Key mismatch! Clearing stale bond...\n");
            bt_unpair(BT_ID_DEFAULT, bt_conn_get_dst(conn));
        }
    }
}


// Struct to pass context into the bond iterator
struct bond_check_ctx {
    const bt_addr_le_t *target_addr;
    bool is_bonded;
};

static void check_bond_cb(const struct bt_bond_info *info, void *user_data)
{
    struct bond_check_ctx *ctx = (struct bond_check_ctx *)user_data;

    // Compare destination address with stored bond identities
    if (bt_addr_le_cmp(&info->addr, ctx->target_addr) == 0) {
        ctx->is_bonded = true;
    }
}

// Check if the connecting address matches a known bond identity in RAM
static bool is_device_bonded(const bt_addr_le_t *addr)
{
    struct bond_check_ctx {
        const bt_addr_le_t *target;
        bool found;
    } ctx = { .target = addr, .found = false };

    auto check_cb = [](const struct bt_bond_info *info, void *user_data) {
        auto *c = (struct bond_check_ctx *)user_data;
        if (bt_addr_le_cmp(&info->addr, c->target) == 0) {
            c->found = true;
        }
    };

    bt_foreach_bond(BT_ID_DEFAULT, check_cb, &ctx);
    return ctx.found;
}
static void connected(struct bt_conn *conn, uint8_t err)
{
    if (err) {
        printk("Connection failed (err %u)\n", err);
        return;
    }

    const bt_addr_le_t *peer_addr = bt_conn_get_dst(conn);
    printk("New peer address =%d",peer_addr);
    if (is_device_bonded(peer_addr)) 
    {
        printk("Central is ALREADY BONDED! Elevating security to encrypt link...");
        
        // Elevate security so stack encrypts using existing LTK
        int sec_err = bt_conn_set_security(conn, BT_SECURITY_L1);
        if (sec_err) {
            printk("Failed to set security level (err %d)", sec_err);
        }
    } else {
        printk("Central is NEW / UNBONDED. Waiting for phone to initiate pairing...");
        /* DO NOT call bt_conn_set_security here! Let the mobile app initiate pairing */
    }
}
static struct bt_conn_cb conn_callbacks = {
    .connected = connected,
    //.disconnected = disconnected,
    .security_changed = security_changed,
};
// Helper callback to populate accept list with existing bonds

// Helper function to dynamically start the 500 ms custom advertising
static void start_custom_advertising(void)
{

    // Check if any bonded device exists
  bt_foreach_bond(BT_ID_DEFAULT, accept_list_bond_cb, NULL);

    // 2. Configure advertising set options to filter requests
    struct bt_le_adv_param adv_param = *BT_LE_ADV_PARAM(
        BT_LE_ADV_OPT_CONN | BT_LE_ADV_OPT_FILTER_CONN,
        BT_GAP_ADV_FAST_INT_MIN_2,
        BT_GAP_ADV_FAST_INT_MAX_2,
        NULL
    );
    // // Define advertising parameters using our custom dynamic identity
    // struct bt_le_adv_param adv_param = {
    //     .id = BT_ID_DEFAULT,       // Use identity created from factory FICR MAC
    //     .sid = 0,
    //     .options = (BT_LE_ADV_OPT_CONN | BT_LE_ADV_OPT_USE_IDENTITY ),
    //     .interval_min = 800,         // 500 ms (800 * 0.625 ms)
    //     .interval_max = 800,         // 500 ms (800 * 0.625 ms)
    //     .peer = NULL,
    // };
// Register this in your setup code:
    bt_conn_cb_register(&conn_callbacks);
    bt_conn_auth_info_cb_register(&auth_info_cb);
    if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
        settings_load(); // Restores keys from flash to RAM
    }
    populate_accept_list_from_stored_bonds();
    int err = bt_le_adv_start(&adv_param, ad, ARRAY_SIZE(ad), NULL, 0);
    if (err) {
        printk("Custom BLE advertising failed to start (err %d)\n", err);
    } else {
        printk("Custom BLE advertising started successfully at 500ms intervals!\n");
    }
}

// Helper function to extract factory MAC and set up Custom Identity
static void init_custom_ble_advertising(void)
{

    
    // bt_addr_le_t addr;

 	// uint8_t mac_addr[6];    
    // // Fetch the 6-byte factory MAC address
    // ssize_t ret = hwinfo_get_device_id(mac_addr, sizeof(mac_addr));
   
    // if (ret > 0) 
    // {
    //     printk("nRF54L15 BLE MAC Address: %02X:%02X:%02X:%02X:%02X:%02X\n",mac_addr[5], mac_addr[4], mac_addr[3], mac_addr[2], mac_addr[1], mac_addr[0]);
    // } 
    // else 
    // {
    //     printk("Failed to read MAC address from FICR.\n");
    // }

    // // Format as a valid Static Random address
	// memcpy(addr.a.val, mac_addr, 6);
	// addr.a.val[0] ^= 0xFF; // Flip the first byte so it doesn't match Matter's default identity
    // addr.type = BT_ADDR_LE_RANDOM;
    // addr.a.val[5] |= 0xC0;
    bt_addr_le_t addr;

// 1. Set address type to LE Random
addr.type = BT_ADDR_LE_RANDOM;

// 2. Fill address bytes with payload/hash
sys_rand_get(addr.a.val, sizeof(addr.a.val));

// 3. Force byte 5 bits to 0b01xxxxxx (0x40 flag)
BT_ADDR_SET_RPA(&addr.a);

// 4. Verify formatting
if (bt_addr_le_is_rpa(&addr)) {
    printk("Address formatted as a valid RPA structure.\n");
}
    // // Create identity in Bluetooth stack (BT stack must already be enabled)
    // int my_identity = bt_id_create(&addr, NULL);
    // if (my_identity < 0) {
    //     printk("Failed to create identity from FICR MAC (err %d). Reverting to default ID.\n", my_identity);
    //     my_adv_identity = BT_ADDR_LE_PUBLIC_ID;
    // } else {
    //     printk("Custom identity %d created using Chip FICR MAC.\n", my_identity);
    //     my_adv_identity = (uint8_t)my_identity;
    // }

    bt_passkey_set(static_passkey);
    printk("Static Passkey set to: %06u\n", static_passkey);
    // Start advertising our custom lock service
    start_custom_advertising();
}
Khodidas Domadiya

Parents Reply Children
No Data
Related