nRF5 SDK is not maintained anymore
More Info: Consider nRF Connect SDK for new designs

When are peer managers connection handles invalidated?

Hi,

I have a central that uses PM to connect to some peripherals.

If I connect to a peer (connection handle 0), and disconnect this device (e.g. by shutting it off). I receive BLE_GAP_EVT_DISCONNECTED and all works fine.

But later when I call

pm_conn_handle_get(peerId, &connHandle);

the connection handle I get is still 0 (zero). But it is not a valid connection handle, since e.g. sd_ble_gap_disconnect() fails with BLE_ERROR_INVALID_CONN_HANDLE. I would expect that om_conn_handle_get() returns me BLE_CONN_HANDLE_INVALID.

Although if I connect to the device 1 (connection handle 0), then disconnect it and connect device 2 (connection handle 0, too because it is reused), pm_conn_handle_get() returns BLE_CONN_HANDLE_INVALID.

In my case this leads to a issue where I think the peer is still connected because the connection handle is valid, but in fact it is not and sd_ble_gap_disconnect() returns BLE_ERROR_INVALID_CONN_HANDLE. Sure, I could ignore this error code, but then something else could go wrong without me noticing it.

I there a way to update the peer manager on disconnects?

Best regards

Parents
  • Hi,

    The Peer Manager uses the Connection state module to check this. Snippet from ble_conn_state.c where connection handles are invalidated:

            case BLE_GAP_EVT_DISCONNECTED:
                record_set_disconnected(conn_handle);
                break;

    What SDK version are you using?

    When do you call pm_conn_handle_get() ? On BLE_GAP_EVT_DISCONNECTED or some other events?

  • Hi,

    I am using SDK version 17.0.2. I don't call pm_conn_handle_get() on BLE_GAP_EVT_DISCONNECTED.

    After disconnect I send an command via BLE nus service to the central to remove the bonds.

    I can verify that this code exists on my side. I guess it is called via

    NRF_SDH_BLE_OBSERVER(m_ble_evt_observer, BLE_CONN_STATE_BLE_OBSERVER_PRIO, ble_evt_handler, NULL);
  • mgux said:
    After disconnect I send an command via BLE nus service to the central to remove the bonds.

     1)So you are in a active connection to another device when you try to delete the bond from the previously connected device?

     2) Can you post the code you use to delete the bond ? 

  •  1)So you are in a active connection to another device when you try to delete the bond from the previously connected device?

    Sorry I was wrong. The command is sent via USB CDC. But it is possible to be connected to another peer while I delete the bond to another one.

    I use this snippet to disconnect (if still connected) and remove the bond:

    // disconnect and remove peer
    uint16_t connHandle = BLE_CONN_HANDLE_INVALID;
    auto ret = pm_conn_handle_get(peerId, &connHandle);
    APP_ERROR_CHECK(ret);
    
    if(connectionHandle == BLE_CONN_HANDLE_INVALID)
    {
        return;
    }
    ret = sd_ble_gap_disconnect(connectionHandle, BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
    
    APP_ERROR_CHECK(ret);
    // The peer got removed from the list of bonds.
    ret = pm_peer_delete(peerId);
    APP_ERROR_CHECK(ret);

  • I can confirm that

    record_set_disconnected(conn_handle);

    is called in ble_conn_state.c.

  • I found some more:

    in ble_conn_state.c:

    typedef struct
    {
        nrf_atflags_t valid_flags;                                 /**< Flags indicating which connection handles are valid. */
        nrf_atflags_t connected_flags;                             /**< Flags indicating which connections are connected, since disconnected connection handles will not immediately be invalidated. */
        nrf_atflags_t central_flags;                               /**< Flags indicating in which connections the local device is the central. */
        nrf_atflags_t encrypted_flags;                             /**< Flags indicating which connections are encrypted. */
        nrf_atflags_t mitm_protected_flags;                        /**< Flags indicating which connections have encryption with protection from man-in-the-middle attacks. */
        nrf_atflags_t lesc_flags;                                  /**< Flags indicating which connections have bonded using LE Secure Connections (LESC). */
        nrf_atflags_t user_flags[BLE_CONN_STATE_USER_FLAG_COUNT];  /**< Flags that can be reserved by the user. The flags will be cleared when a connection is invalidated, otherwise, the user is wholly responsible for the flag states. */
    } ble_conn_state_flag_collections_t;

    static void record_set_disconnected(uint16_t conn_handle)
    {
        nrf_atflags_clear(&m_bcs.flags.connected_flags, conn_handle);
    }

    bool ble_conn_state_valid(uint16_t conn_handle)
    {
        if (conn_handle >= BLE_CONN_STATE_MAX_CONNECTIONS)
        {
            return false;
        }
        return nrf_atflags_get(&m_bcs.flags.valid_flags, conn_handle);
    }

    ble_conn_state_valid() is used in pm_conn_handle_get() and checks the valid_flags.. But record_set_disconnected() clears the connected flag not the valid_flags.

    Also the comment for connected_flags says that connection handles will no immediately be invalidated.

    So maybe one should check the connected flag in pm_conn_handle_get()?

  • mgux said:
    I use this snippet to disconnect

    Seems like you are using both connectionHandle and connHandle?

    Try this instead:

    // disconnect and remove peer
    uint16_t connHandle = BLE_CONN_HANDLE_INVALID;
    auto ret = pm_conn_handle_get(peerId, &connHandle);
    APP_ERROR_CHECK(ret);
    
    if(connHandle == BLE_CONN_HANDLE_INVALID)
    {
        return;
    }
    ret = sd_ble_gap_disconnect(connHandle, BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
    
    APP_ERROR_CHECK(ret);
    // The peer got removed from the list of bonds.
    ret = pm_peer_delete(peerId);
    APP_ERROR_CHECK(ret);

Reply
  • mgux said:
    I use this snippet to disconnect

    Seems like you are using both connectionHandle and connHandle?

    Try this instead:

    // disconnect and remove peer
    uint16_t connHandle = BLE_CONN_HANDLE_INVALID;
    auto ret = pm_conn_handle_get(peerId, &connHandle);
    APP_ERROR_CHECK(ret);
    
    if(connHandle == BLE_CONN_HANDLE_INVALID)
    {
        return;
    }
    ret = sd_ble_gap_disconnect(connHandle, BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
    
    APP_ERROR_CHECK(ret);
    // The peer got removed from the list of bonds.
    ret = pm_peer_delete(peerId);
    APP_ERROR_CHECK(ret);

Children
Related