Reasons why bonds are deleted?

We have a custom board in production, which is nRF52832, s132, nrf5 SDK. 

Below I provide you some code regarding the peer manager. We use a static key to pair and connect to the devices. Usually only one device will connect to the board. 

We recently have faced some issues regarding connection from our clients. The error 0x1006 from security fail event from peer manager is triggered, and the solution is always to unpair and pair again from the mobile phone. But, we cannot understand why this happens, what can trigger the bonds to be deleted? Or is there a way that we can track the reason from the event  PM_EVT_PEERS_DELETE_SUCCEEDED? 

The peer manager initialization:

/**@brief Function for the Peer Manager initialization.
 */
static void peer_manager_init(void)
{
    ble_gap_sec_params_t sec_param;
    ret_code_t           err_code;

    err_code = pm_init();
    hardfault = app_error_check_logger(err_code, true, log_str[PEER_MANAGER_INIT], 0, NULL);

    memset(&sec_param, 0, sizeof(ble_gap_sec_params_t));

    // Security parameters to be used for all security procedures. These are common parameters for bonding.
    sec_param.bond           = 1;
    sec_param.mitm           = 0;
    sec_param.lesc           = 0;
    sec_param.keypress       = 0;
    sec_param.io_caps        = BLE_GAP_IO_CAPS_DISPLAY_ONLY;
    sec_param.oob            = 0;
    sec_param.min_key_size   = 7;
    sec_param.max_key_size   = 16;
    sec_param.kdist_own.enc  = 1;
    sec_param.kdist_own.id   = 1;
    sec_param.kdist_peer.enc = 1;
    sec_param.kdist_peer.id  = 1;

    err_code = pm_sec_params_set(&sec_param);   // sets security parameters for pairing and bonding
    hardfault = app_error_check_logger(err_code, true, log_str[PEER_MANAGER_INIT], 1, NULL);

    err_code = pm_register(pm_evt_handler);   // register an event handler for the module
    hardfault = app_error_check_logger(err_code, true, log_str[PEER_MANAGER_INIT], 2, NULL);
}

The peer manager event handler :

static void pm_evt_handler(pm_evt_t const * p_evt)
{
    pm_handler_on_pm_evt(p_evt);    // Logging peer events. Starts encryption if connected to a bonded device.
    pm_handler_disconnect_on_sec_failure(p_evt);    // Disconnects if the connection was not secured.
    pm_handler_flash_clean(p_evt);

    switch (p_evt->evt_id)
    {
        case PM_EVT_CONN_SEC_SUCCEEDED:   //a link has been encrypted, result of a call of pm_conn_secure or of an action by the peer.
            m_peer_id = p_evt->peer_id;
            pm_local_database_has_changed();
            break;

        case PM_EVT_PEERS_DELETE_SUCCEEDED:   // a peer was cleared from flash storage (result of pm_peer_delete)
            NRF_LOG_INFO("PM_EVT_PEERS_DELETE_SUCCEEDED");
            hardfault = app_error_check_logger(1, false, "peersdel", 1, NULL);
            advertising_start(false);
            break;

        case PM_EVT_PEER_DATA_UPDATE_SUCCEEDED: // a piece of peer data was tored, updated or cleared in flash storage.
            if (     p_evt->params.peer_data_update_succeeded.flash_changed
                 && (p_evt->params.peer_data_update_succeeded.data_id == PM_PEER_DATA_ID_BONDING))
            {
                NRF_LOG_INFO("New Bond. Peer data update succeeded.");
            }
            break;
        case PM_EVT_CONN_SEC_FAILED:    // a pairing or encryption procedure has failed. in some cases, this means that security is not possible on this link.
        {
            NRF_LOG_INFO("Pairing or Encryption procedure failed. Peer id=%d, Error=%x, Procedure=%d, Source=%d", p_evt->peer_id, p_evt->params.conn_sec_failed.error,
                                                                                        p_evt->params.conn_sec_failed.procedure,p_evt->params.conn_sec_failed.error_src);
            uint8_t proc=0;
            if(p_evt->params.conn_sec_failed.error_src == 1)
            {
                  proc = p_evt->params.conn_sec_failed.procedure + 10;
            }
            else
            {
                  proc = p_evt->params.conn_sec_failed.procedure;
            }
            hardfault = app_error_check_logger(p_evt->params.conn_sec_failed.error, false, "secfail", proc, NULL);
            m_scoliosense.err_code = p_evt->params.conn_sec_failed.error;
            ble_error_sec_update(m_conn_handle, &m_scoliosense);
         }
            break;
         case PM_EVT_CONN_SEC_CONFIG_REQ:
         {
            // Allow or reject pairing request from an already bonded peer.
            NRF_LOG_INFO("Repairing Process was initiated.");
            pm_conn_sec_config_t conn_sec_config = {.allow_repairing = true};
            pm_conn_sec_config_reply(p_evt->conn_handle, &conn_sec_config);
         } 
         break;

        default:
            break;
    }
}

Any help is much appreciated! 

Best regards,
Dimitra

  • Hello Dimitra,

    The Peer Manager can be configured to delete the oldest bond to free up space in FDS for new bonds. This works fine as long as FDS is only used for storing bonding information. However, if FDS is also used for storing other application data, there is a possibility that the Peer Manager could be forced to delete the last and only bond. So, are you using FDS for storing other data in your application?

    Best regards,

    Vidar

  • Yes we use FDS to save application data in flash. 

    So, does this mean that there is a way to configure the peer manager to never delete the only one bond of the device or I should keep track of the free memory, and stop saving data early enough before the flash is trully full, and then peer manager will not be forced to delete the last and only bond? How can I do this, or where can I find how much space peer manager needs so that it never deletes the bonds? Or is there another way to handle this situation in general?


    best regards,
    Dimitra

  • Hi Dimitra,

    I think the easiest solution may be to periodically monitor the flash usage with the fds_stat() function and perform GC or freeing of records before the FDS becomes full.

    Best regards,

    Vidar

  • Ok, so there is not any other reason why the bonds might be deleted? \the only way is that the peer manager deletes them and it does it when there is no enough space. 

  • It depends on your implementation. Apart from calling pm_handler_flash_clean() in your pm event handler, do you have any other mechanisms for deleting bonds in your firmware? In the SDK examples, bonds are typically deleted if board button 1 is pressed at startup.

    /**@brief Auxiliary standard function for maintaining room in flash based on Peer Manager events.
     *
     * This function does the following:
     *  - Ranks peers by when they last connected.
     *  - Garbage collects the flash when needed.
     *  - Deletes the lowest ranked peer(s) when garbage collection is insufficient.
     *
     * @note See also @ref pm_handler_flash_clean_on_return.
     * @note In normal circumstances, this function should be called for every Peer Manager event.
     * @note This function is a supplement to @ref pm_handler_on_pm_evt, not its replacement.
     *
     * @param[in]  p_pm_evt  Peer Manager event to handle.
     */
    void pm_handler_flash_clean(pm_evt_t const * p_pm_evt);

Related