This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

DFU with extra authentication

Hello, I want to put extra authentication when device is preparing for boot loader. I found callback  "ble_dfu_evt_handler". I think inside case  BLE_DFU_EVT_BOOTLOADER_ENTER_PREPARE , I can add that condition like below:

        case BLE_DFU_EVT_BOOTLOADER_ENTER_PREPARE:
        {
            NRF_LOG_INFO("Device is preparing to enter bootloader mode.");
            
            if(authentication_condition != true ){
                stop_DFU_api();
            }{
                // Prevent device from advertising on disconnect.
                ble_adv_modes_config_t config;
                advertising_config_get(&config);
                config.ble_adv_on_disconnect_disabled = true;
                ble_advertising_modes_config_set(&m_advertising, &config);

                // Disconnect all other bonded devices that currently are connected.
                // This is required to receive a service changed indication
                // on bootup after a successful (or aborted) Device Firmware Update.
                uint32_t conn_count = ble_conn_state_for_each_connected(disconnect, NULL);
                NRF_LOG_INFO("Disconnected %d links.", conn_count);
            }
            break;
        }

I am unable to find api to stop DFU process. Please suggest. Also let me know if this is correct way of doing same.

Thanks

  • HI Chandan, 

    the BLE_DFU_EVT_BOOTLOADER_ENTER_PREPARE event will be generated when ble_dfu_buttonless_bootloader_start_prepare is called. 

    uint32_t ble_dfu_buttonless_bootloader_start_prepare(void)
    {
        uint32_t err_code;
    
        // Indicate to main app that DFU mode is starting.
        mp_dfu->evt_handler(BLE_DFU_EVT_BOOTLOADER_ENTER_PREPARE);
    
        err_code = ble_dfu_buttonless_bootloader_start_finalize();
        return err_code;
    }

    As you can see ble_dfu_buttonless_bootloader_start_finalize() is called when the evt_handler has returned. So if you want to prevent the device from entering bootloader moder, then you will have to set a flag or similar when the extra authentication fails and then check this in ble_dfu_buttonless_bootloader_start_prepare() after the evt_handler has returned. One way to do this is as follows:

    uint32_t ble_dfu_buttonless_bootloader_start_prepare(void)
    {
        uint32_t err_code;
    
        // Indicate to main app that DFU mode is starting.
        mp_dfu->evt_handler(BLE_DFU_EVT_BOOTLOADER_ENTER_PREPARE);
        
        if(authentication_ok)
        {
            err_code = ble_dfu_buttonless_bootloader_start_finalize();
            return err_code;
        }else
        {
            //Authentication failed. Do not enter bootloader mode
            return NRF_ERROR_FORBIDDEN;
        }
    }

    Best regards

    Bjørn

  • Thanks for quick reply.

    I don't want to make change in any SDK file. Its difficult to update same change in all member's SDK file. Please suggest similar to callback function change.

  • Hi Chandan, 

    from the point you receive the BLE_DFU_EVT_BOOTLOADER_ENTER_PREPARE event, then there is no way to halt the reset process with out modifying the SDK source as ble_dfu_buttonless_bootloader_start_finalize will be called immediately after the evt_handler, i.e. ble_dfu_evt_handler()  returns. As you see below ble_dfu_buttonless_bootloader_start_finalize() calls nrf_pwr_mgmt_shutdown(NRF_PWR_MGMT_SHUTDOWN_GOTO_DFU) and there is no API in the power management module to abort this. 

    uint32_t ble_dfu_buttonless_bootloader_start_finalize(void)
    {
        uint32_t err_code;
    
        NRF_LOG_DEBUG("In ble_dfu_buttonless_bootloader_start_finalize\r\n");
    
        err_code = sd_power_gpregret_clr(0, 0xffffffff);
        VERIFY_SUCCESS(err_code);
    
        err_code = sd_power_gpregret_set(0, BOOTLOADER_DFU_START);
        VERIFY_SUCCESS(err_code);
    
        // Indicate that the Secure DFU bootloader will be entered
        m_dfu.evt_handler(BLE_DFU_EVT_BOOTLOADER_ENTER);
    
        // Signal that DFU mode is to be enter to the power management module
        nrf_pwr_mgmt_shutdown(NRF_PWR_MGMT_SHUTDOWN_GOTO_DFU);
    
        return NRF_SUCCESS;
    }

    So its not possible to prevent the reset, but it is possible to make the device boot straight back to the application by calling sd_power_gpregret_clr(0, 0xffffffff) when you get the  BLE_DFU_EVT_BOOTLOADER_ENTER event. The GPREGRET register is checked by the bootloader and if it does not contain the BOOTLOADER_DFU_START value, then the bootloader will jump to the application. 

    Best regards

    Bjørn

  • I tried below code, when authentication_ok is false,  NRF doesn't start DFU and disconnect device but post NRF stop BLE advertisement. I tried calling  event handler post authentication check.

    uint32_t ble_dfu_buttonless_bootloader_start_prepare(void)
    {
        uint32_t err_code;
    
        // Indicate to main app that DFU mode is starting.
        mp_dfu->evt_handler(BLE_DFU_EVT_BOOTLOADER_ENTER_PREPARE);
        
        if(authentication_ok)
        {
            err_code = ble_dfu_buttonless_bootloader_start_finalize();
            return err_code;
        }else
        {
            //Authentication failed. Do not enter bootloader mode
            return NRF_ERROR_FORBIDDEN;
        }
    }

  • If ble_dfu_buttonless_bootloader_start_prepare returns a non-zero error code, then the ble_dfu_evt_handler() will be called with the as BLE_DFU_EVT_BOOTLOADER_ENTER_FAILED as the event type. 

    static void on_hvc(ble_evt_t const * p_ble_evt)
    {
        uint32_t err_code;
        ble_gatts_evt_hvc_t const * p_hvc = &p_ble_evt->evt.gatts_evt.params.hvc;
    
        if (p_hvc->handle == m_dfu.control_point_char.value_handle)
        {
            // Enter bootloader if we were waiting for reset after hvc indication confimation.
            if (m_dfu.is_waiting_for_reset)
            {
                err_code = ble_dfu_buttonless_bootloader_start_prepare();
                if (err_code != NRF_SUCCESS)
                {
                    m_dfu.evt_handler(BLE_DFU_EVT_BOOTLOADER_ENTER_FAILED);
                }
            }
        }
    }

    Hence, you can restart advertisment in ble_dfu_evt_handler() under case BLE_DFU_EVT_BOOTLOADER_ENTER_FAILED:

Related