/** * Copyright (c) 2016 - 2018, Nordic Semiconductor ASA * * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * 2. Redistributions in binary form, except as embedded into a Nordic * Semiconductor ASA integrated circuit in a product or a software update for * such product, must reproduce the above copyright notice, this list of * conditions and the following disclaimer in the documentation and/or other * materials provided with the distribution. * * 3. Neither the name of Nordic Semiconductor ASA nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * 4. This software, with or without modification, must only be used with a * Nordic Semiconductor ASA integrated circuit. * * 5. Any software provided in binary form under this license must not be reverse * engineered, decompiled, modified and/or disassembled. * * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #include "sdk_common.h" #if NRF_MODULE_ENABLED(RNG) #include #include #include "nrf_drv_rng.h" #include "nordic_common.h" #include "app_util_platform.h" #include "nrf_assert.h" #include "nrf_queue.h" #ifdef SOFTDEVICE_PRESENT #include "nrf_sdh.h" #endif // SOFTDEVICE_PRESENT #define NRF_LOG_MODULE_NAME rng #if RNG_CONFIG_LOG_ENABLED #define NRF_LOG_LEVEL RNG_CONFIG_LOG_LEVEL #define NRF_LOG_INFO_COLOR RNG_CONFIG_INFO_COLOR #define NRF_LOG_DEBUG_COLOR RNG_CONFIG_DEBUG_COLOR #else //RNG_CONFIG_LOG_ENABLED #define NRF_LOG_LEVEL 0 #endif //RNG_CONFIG_LOG_ENABLED #include "nrf_log.h" NRF_LOG_MODULE_REGISTER(); typedef struct { nrfx_drv_state_t state; nrf_drv_rng_config_t config; } nrf_drv_rng_cb_t; static nrf_drv_rng_cb_t m_rng_cb; NRF_QUEUE_DEF(uint8_t, m_rand_pool, RNG_CONFIG_POOL_SIZE, NRF_QUEUE_MODE_OVERFLOW); static const nrf_drv_rng_config_t m_default_config = NRF_DRV_RNG_DEFAULT_CONFIG; #ifdef SOFTDEVICE_PRESENT #define SD_RAND_POOL_SIZE (64) STATIC_ASSERT(RNG_CONFIG_POOL_SIZE == SD_RAND_POOL_SIZE); #define NRF_DRV_RNG_LOCK() CRITICAL_REGION_ENTER() #define NRF_DRV_RNG_RELEASE() CRITICAL_REGION_EXIT() #define NRF_DRV_RNG_SD_IS_ENABLED() nrf_sdh_is_enabled() #else #define NRF_DRV_RNG_LOCK() do { } while (0) #define NRF_DRV_RNG_RELEASE() do { } while (0) #define NRF_DRV_RNG_SD_IS_ENABLED() false #endif // SOFTDEVICE_PRESENT static void nrfx_rng_handler(uint8_t rng_val) { NRF_DRV_RNG_LOCK(); if (!NRF_DRV_RNG_SD_IS_ENABLED()) { UNUSED_RETURN_VALUE(nrf_queue_push(&m_rand_pool, &rng_val)); if (nrf_queue_is_full(&m_rand_pool)) { nrfx_rng_stop(); } NRF_LOG_DEBUG("Event: NRF_RNG_EVENT_VALRDY."); } NRF_DRV_RNG_RELEASE(); } ret_code_t nrf_drv_rng_init(nrf_drv_rng_config_t const * p_config) { ret_code_t err_code = NRF_SUCCESS; if (m_rng_cb.state != NRFX_DRV_STATE_UNINITIALIZED) { return NRF_ERROR_MODULE_ALREADY_INITIALIZED; } if (p_config == NULL) { p_config = &m_default_config; } m_rng_cb.config = *p_config; NRF_DRV_RNG_LOCK(); if (!NRF_DRV_RNG_SD_IS_ENABLED()) { err_code = nrfx_rng_init(&m_rng_cb.config, nrfx_rng_handler); if (err_code != NRF_SUCCESS) { return err_code; } nrfx_rng_start(); } m_rng_cb.state = NRFX_DRV_STATE_INITIALIZED; NRF_DRV_RNG_RELEASE(); return err_code; } void nrf_drv_rng_uninit(void) { ASSERT(m_rng_cb.state == NRFX_DRV_STATE_INITIALIZED); NRF_DRV_RNG_LOCK(); if (!NRF_DRV_RNG_SD_IS_ENABLED()) { nrfx_rng_stop(); nrfx_rng_uninit(); } NRF_DRV_RNG_RELEASE(); nrf_queue_reset(&m_rand_pool); m_rng_cb.state = NRFX_DRV_STATE_UNINITIALIZED; NRF_LOG_INFO("Uninitialized."); } void nrf_drv_rng_bytes_available(uint8_t * p_bytes_available) { ASSERT(m_rng_cb.state == NRFX_DRV_STATE_INITIALIZED); #ifdef SOFTDEVICE_PRESENT if (NRF_DRV_RNG_SD_IS_ENABLED()) { if (NRF_SUCCESS == sd_rand_application_bytes_available_get(p_bytes_available)) { return; } } #endif // SOFTDEVICE_PRESENT *p_bytes_available = nrf_queue_utilization_get(&m_rand_pool); NRF_LOG_INFO("Function: %s, available bytes: %d.", (uint32_t)__func__, *p_bytes_available); } ret_code_t nrf_drv_rng_rand(uint8_t * p_buff, uint8_t length) { ret_code_t err_code = NRF_SUCCESS; ASSERT(m_rng_cb.state == NRFX_DRV_STATE_INITIALIZED); #ifdef SOFTDEVICE_PRESENT do { bool sd_is_enabled; NRF_DRV_RNG_LOCK(); sd_is_enabled = NRF_DRV_RNG_SD_IS_ENABLED(); if (!sd_is_enabled) #endif // SOFTDEVICE_PRESENT { err_code = nrf_queue_read(&m_rand_pool, p_buff, (uint32_t)length); nrfx_rng_start(); } #ifdef SOFTDEVICE_PRESENT NRF_DRV_RNG_RELEASE(); if (sd_is_enabled) { err_code = sd_rand_application_vector_get(p_buff, length); if (err_code == NRF_ERROR_SOC_RAND_NOT_ENOUGH_VALUES) { err_code = NRF_ERROR_NOT_FOUND; } } } while (err_code == NRF_ERROR_SOFTDEVICE_NOT_ENABLED); #endif // SOFTDEVICE_PRESENT ASSERT((err_code == NRF_SUCCESS) || (err_code == NRF_ERROR_NOT_FOUND)); #if defined(RNG_CONFIG_RANDOM_NUMBER_LOG_ENABLED) && (RNG_CONFIG_RANDOM_NUMBER_LOG_ENABLED != 0) NRF_LOG_DEBUG("Rand buffer data:"); NRF_LOG_HEXDUMP_DEBUG((uint8_t *)p_buff, length); #endif // RNG_CONFIG_RANDOM_NUMBER_LOG_ENABLED NRF_LOG_WARNING("Function: %s, error code: %s.", (uint32_t)__func__, (uint32_t)NRF_LOG_ERROR_STRING_GET(err_code)); return err_code; } void nrf_drv_rng_block_rand(uint8_t * p_buff, uint32_t length) { ASSERT(m_rng_cb.state == NRFX_DRV_STATE_INITIALIZED); while (length) { uint32_t len = MIN(length, RNG_CONFIG_POOL_SIZE); ret_code_t err_code; do { err_code = nrf_drv_rng_rand(p_buff, len); } while (err_code != NRF_SUCCESS); length -= len; p_buff += len; } NRF_LOG_DEBUG("Rand buffer data:"); NRF_LOG_HEXDUMP_DEBUG((uint8_t *)p_buff, length); } #ifdef SOFTDEVICE_PRESENT static void sd_state_evt_handler(nrf_sdh_state_evt_t state, void * p_context) { switch (state) { case NRF_SDH_EVT_STATE_ENABLE_PREPARE: if (m_rng_cb.state == NRFX_DRV_STATE_INITIALIZED) { nrfx_rng_stop(); nrfx_rng_uninit(); } break; case NRF_SDH_EVT_STATE_DISABLED: NRF_DRV_RNG_LOCK(); if (m_rng_cb.state == NRFX_DRV_STATE_INITIALIZED) { ret_code_t err_code = nrfx_rng_init(&m_rng_cb.config, nrfx_rng_handler); if (err_code != NRF_SUCCESS) { ASSERT(false); } nrfx_rng_start(); } NRF_DRV_RNG_RELEASE(); break; default: break; } } NRF_SDH_STATE_OBSERVER(m_sd_state_observer, RNG_CONFIG_STATE_OBSERVER_PRIO) = { .handler = sd_state_evt_handler, .p_context = NULL, }; #endif // SOFTDEVICE_PRESENT #endif // NRF_MODULE_ENABLED(RNG)