Connection security level is stuck at level 1 after it had successfully paired (with confirmed connection security level 4) with an iPhone.

Hi,

My development environment:

- VS Code

- nRF Connect SDK: v2.7.0

Description:

- My firmware had successfully paired (with passcode) with an iPhone. Security level reaches level 4 as expected. BLE advertising is setup with accept_list to make sure only the paired Central can connect.

- After paired, it works for a few hours.

- Sometimes only : when reconnecting, security level is only level 1, and stick to level 1 forever.

- When the connection security level is stick to level 1, printing its connection info crashes the app although `bt_conn_get_info()` return success. Please refer to `print_connection_params()` below.

Outline of my code:

int main(void)
{
    ...
    int err = init_ecg_bluetooth();
	if (err)
	{
		LOG_ERR("bt_enable error returned: %d", err);
		return 0;
	}
	...
}

static struct bt_conn *current_conn = NULL;

static void on_connected(struct bt_conn *conn, uint8_t err)
{
    if (err)
    {
        LOG_ERR("Connection failed (err 0x%02x)\n", err);
    }
    else
    {
        LOG_INF("Connected\n");

        current_conn = bt_conn_ref(conn);
        print_connection_params(current_conn);
    }
}

static void on_disconnected(struct bt_conn *conn, uint8_t reason)
{
    // C:\ncs\v2.4.0\zephyr\include\zephyr\bluetooth\hci_err.h
    LOG_INF("Disconnected (reason 0x%02x)\n", reason);

    bt_conn_unref(current_conn);
    current_conn = NULL;
    ...
}

static void on_security_changed(struct bt_conn *conn, bt_security_t level, enum bt_security_err error)
{
    if (error != BT_SECURITY_ERR_SUCCESS)
    {
        LOG_ERR("failed to upgrade security: %d", error);
        ...
        return;
    }

    ...

    LOG_INF("connection security upgraded: %d -> %d", level, is_conn_secured());

    ...
}

/**
 * @brief This only gets called for the first pairing.
 *        Since then, only @ref on_security_changed() is called.
 *
 * @param conn
 * @param bonded
 */
static void on_pairing_complete(struct bt_conn *conn, bool bonded)
{
    LOG_INF("bonded: %d", bonded);
    if (bonded)
    {
        ...

        bt_foreach_bond(BT_ID_DEFAULT, copy_last_bond_addr, NULL);
        print_addr_le(bond_addr, "bonded addr");

        ...
    }
}

static void on_pairing_failed(struct bt_conn *conn, enum bt_security_err reason)
{
    LOG_ERR("pairing failed: %d", reason);

    ...
}

void print_connection_params(struct bt_conn *conn)
{
    struct bt_conn_info info;
    int err = bt_conn_get_info(conn, &info);
    if (err < 0)
    {
        LOG_ERR("Failed to get connection info: %d", err); // this line never prints!
    }
    else
    {
        LOG_INF("Connection params: interval %d*1.25ms, latency %d, timeout %d*10ms, security: %d",
                info.le.interval, info.le.latency, info.le.timeout,
                info.security.level); // ! crash here! this line never prints
    }
}

// Function below is triggered on a button press
void print_ecg_ble_state()
{
    print_addr_le(bond_addr, "bonded addr"); // this line prints
    ...
    
    if (current_conn)
    {
        LOG_INF("conn available with security level: %d %d %d",
                bt_conn_get_security(current_conn),
                is_streaming, // our app variable
                conn_param); // this line prints: 1 0 2
        print_connection_params(current_conn);
    }
    else
    {
        LOG_INF("conn not available"); // this does not print
    }

    ...
}

My questions:

  1. Why only sometimes, on reconnecting, BLE stack fails to upgrade the security level from 1 to 4? It sticks to level 1 forever until the system crashes (causing reboot). After reboot, the system works as normal. This symptom is confirmed when this app works with both iPhone and ESP32S3 acting as Central.
  2. As you may notice, `print_connection_params()` is called with `current_conn` in `on_connected()`. After the connection is stick with level 1 forever (error state), calling `print_connection_params()` on the referenced `current_conn` crashes the app. Why is this? 
  3. Connection upgrade is done at the nRF BLE stack level, is connection forever stick to security level 1 because something's wrong with this nRF SDK Connect v2.7.0?

Best regards,

Quan

Parents
  • Hi Amanda,

    Of course, we did have those settings turned on to get the pairing feature work:

    CONFIG_SETTINGS=y
    CONFIG_BT_SETTINGS=y
    CONFIG_FLASH=y
    CONFIG_FLASH_PAGE_LAYOUT=y
    CONFIG_FLASH_MAP=y
    CONFIG_NVS=y

    After it had paired with a Central (an iPhone or ESP32S3), it worked for a few hours (power-resetting the board still gets the Central reconnected successfully). Just sometimes, the connection is stuck at level 1, the Central is not populated with connected event (such as in iOS, Bluetooth Settings, the device is shown as Not Connected). In this error state, if I print out the connection info, application crash as I had mentioned above.   

    Just a reminder: since we do use Accept list feature, there is no other device can connect to it, except for the paired Central (my device only accepts 1 pair:

    `CONFIG_BT_MAX_PAIRED=1`

    )

  • It sticks to level 1 forever until the system crashes (causing reboot).

    Could you provide the log?

  • Amanda,

    I have minimized the log printout into the attached screenshot. This log is printed when a single click on a button is triggered.

    When the single click is triggered, this function is called: 

    void print_ecg_ble_state()
    {
        print_data(sys_data, SYS_DATA_TOTAL_LEN, "sys_data");
    
        print_addr_le(bond_addr, "bonded addr");
        if (is_bonded()) // LED is currently off
        {
            led_start_blinking(LED_BLINK_CHECK_ALIVE, 3000);
        }
        // else, LED is blinking with pattern @ref LED_BLINK_PATTERN_BOND_CLEARED
    
        if (current_conn)
        {
            LOG_INF("conn available with security level: %d %d %d",
                    bt_conn_get_security(current_conn),
                    is_streaming,
                    conn_param);
            print_connection_params(current_conn); // it goes here!!!
        }
        else
        {
            LOG_INF("conn not available");
        }
    
        print_remaining_time(&hold_adv_timer, "hold_adv_timer");
        LOG_INF("pairing attempt: %d", pairing_attempt_count);
    
        LOG_INF("NAND info\n\taddr: 0x%08x, mode: %d, pktnum: %d",
                NAND_Addr,
                NAND_mode,
                Pkt_num);
        if (NAND_mode == 1)
        {
            LOG_INF("NOfflen: %d", NOff_len);
        }
    }
    
    void print_connection_params(struct bt_conn *conn)
    {
        struct bt_conn_info info;
        int err = bt_conn_get_info(conn, &info);
        if (err < 0)
        {
            LOG_ERR("Failed to get connection info: %d", err); // this line does not print!
        }
        else
        {
            LOG_INF("Connection params: interval %d*1.25ms, latency %d, timeout %d*10ms, security: %d",
                    info.le.interval, info.le.latency, info.le.timeout,
                    info.security.level);
        }
    }

    As in the green annotation line, `current_conn` is available with the printed security level at level 1.

    `current_conn` is only established and referenced by `bt_conn_ref()` in `on_connected()` event. And `bt_conn_unref()` in `on_disconnected()` event

    (Please refer to my original post for how I used it)

    I can confirm that while in this error state, no other BLE scanner can "see" it (my device only accepts 1 connection).

    When connection is made, the BLE stack should have been transitioned its security level from 1 to 4 without any interactions from the app. But in this error state, nothing happened after connection is established between the iPhone Central and my device (acting as a Peripheral).

    What could have happened?

    Best regards,

Reply
  • Amanda,

    I have minimized the log printout into the attached screenshot. This log is printed when a single click on a button is triggered.

    When the single click is triggered, this function is called: 

    void print_ecg_ble_state()
    {
        print_data(sys_data, SYS_DATA_TOTAL_LEN, "sys_data");
    
        print_addr_le(bond_addr, "bonded addr");
        if (is_bonded()) // LED is currently off
        {
            led_start_blinking(LED_BLINK_CHECK_ALIVE, 3000);
        }
        // else, LED is blinking with pattern @ref LED_BLINK_PATTERN_BOND_CLEARED
    
        if (current_conn)
        {
            LOG_INF("conn available with security level: %d %d %d",
                    bt_conn_get_security(current_conn),
                    is_streaming,
                    conn_param);
            print_connection_params(current_conn); // it goes here!!!
        }
        else
        {
            LOG_INF("conn not available");
        }
    
        print_remaining_time(&hold_adv_timer, "hold_adv_timer");
        LOG_INF("pairing attempt: %d", pairing_attempt_count);
    
        LOG_INF("NAND info\n\taddr: 0x%08x, mode: %d, pktnum: %d",
                NAND_Addr,
                NAND_mode,
                Pkt_num);
        if (NAND_mode == 1)
        {
            LOG_INF("NOfflen: %d", NOff_len);
        }
    }
    
    void print_connection_params(struct bt_conn *conn)
    {
        struct bt_conn_info info;
        int err = bt_conn_get_info(conn, &info);
        if (err < 0)
        {
            LOG_ERR("Failed to get connection info: %d", err); // this line does not print!
        }
        else
        {
            LOG_INF("Connection params: interval %d*1.25ms, latency %d, timeout %d*10ms, security: %d",
                    info.le.interval, info.le.latency, info.le.timeout,
                    info.security.level);
        }
    }

    As in the green annotation line, `current_conn` is available with the printed security level at level 1.

    `current_conn` is only established and referenced by `bt_conn_ref()` in `on_connected()` event. And `bt_conn_unref()` in `on_disconnected()` event

    (Please refer to my original post for how I used it)

    I can confirm that while in this error state, no other BLE scanner can "see" it (my device only accepts 1 connection).

    When connection is made, the BLE stack should have been transitioned its security level from 1 to 4 without any interactions from the app. But in this error state, nothing happened after connection is established between the iPhone Central and my device (acting as a Peripheral).

    What could have happened?

    Best regards,

Children
Related