From d90095b5561a287e53e15a98250e15574fe9ffaa Mon Sep 17 00:00:00 2001 From: Vinayak Kariappa Chettimada Date: Mon, 7 Aug 2017 12:12:39 +0200 Subject: [PATCH] Bluetooth: controller: Use random numbers in adv and enc setup Added implementation to get random numbers in ISR. And fixed implementation to use random numbers in advertisement random delay and encryption setup procedure. Signed-off-by: Vinayak Kariappa Chettimada --- subsys/bluetooth/controller/hal/nrf5/rand.c | 145 +++++++++++++------- subsys/bluetooth/controller/hal/rand.h | 4 +- subsys/bluetooth/controller/ll_sw/ctrl.c | 54 +++----- subsys/bluetooth/controller/ll_sw/ll.c | 9 +- 4 files changed, 126 insertions(+), 86 deletions(-) diff --git a/subsys/bluetooth/controller/hal/nrf5/rand.c b/subsys/bluetooth/controller/hal/nrf5/rand.c index 3795934a5c9..f573da0dc0d 100644 --- a/subsys/bluetooth/controller/hal/nrf5/rand.c +++ b/subsys/bluetooth/controller/hal/nrf5/rand.c @@ -12,36 +12,55 @@ #include "common/log.h" #include "hal/debug.h" -#define RAND_RESERVED (4) - struct rand { u8_t count; + u8_t threshold; u8_t first; u8_t last; u8_t rand[1]; }; -static struct rand *rng; +static struct rand *rng_isr; +static struct rand *rng_thr; -void rand_init(u8_t *context, u8_t context_len) +static void init(struct rand **rng, u8_t *context, u8_t len, u8_t threshold) { - LL_ASSERT(context_len > sizeof(struct rand)); + struct rand *p; - rng = (struct rand *)context; - rng->count = context_len - sizeof(struct rand) + 1; - rng->first = rng->last = 0; + LL_ASSERT(len > (offsetof(struct rand, rand) + threshold)); - NRF_RNG->CONFIG = RNG_CONFIG_DERCEN_Msk; - NRF_RNG->EVENTS_VALRDY = 0; - NRF_RNG->INTENSET = RNG_INTENSET_VALRDY_Msk; + *rng = (struct rand *)context; - NRF_RNG->TASKS_START = 1; + p = *rng; + p->count = len - offsetof(struct rand, rand); + p->threshold = threshold; + p->first = p->last = 0; + + if (!rng_isr || !rng_thr) { + NRF_RNG->CONFIG = RNG_CONFIG_DERCEN_Msk; + NRF_RNG->EVENTS_VALRDY = 0; + NRF_RNG->INTENSET = RNG_INTENSET_VALRDY_Msk; + + NRF_RNG->TASKS_START = 1; + } } -size_t rand_get(size_t octets, u8_t *rand) +void rand_init(u8_t *context, u8_t context_len, u8_t threshold) +{ + init(&rng_thr, context, context_len, threshold); +} + +void rand_isr_init(u8_t *context, u8_t context_len, u8_t threshold) +{ + init(&rng_isr, context, context_len, threshold); +} + +static size_t get(struct rand *rng, size_t octets, u8_t *rand) { - u8_t reserved; u8_t first; + u8_t avail; + + LL_ASSERT(rng); while (octets) { if (rng->first == rng->last) { @@ -57,59 +76,83 @@ size_t rand_get(size_t octets, u8_t *rand) rng->first = first; } - reserved = RAND_RESERVED; - first = rng->first; - while (reserved--) { - if (first == rng->last) { - NRF_RNG->TASKS_START = 1; + if (rng->first <= rng->last) { + avail = rng->last - rng->first; + } else { + avail = rng->count - rng->first + rng->last; + } - break; - } - - first++; - if (first == rng->count) { - first = 0; - } + if (avail < rng->threshold) { + NRF_RNG->TASKS_START = 1; } return octets; } +size_t rand_get(size_t octets, u8_t *rand) +{ + return get(rng_thr, octets, rand); +} + +size_t rand_isr_get(size_t octets, u8_t *rand) +{ + return get(rng_isr, octets, rand); +} + +static int isr(struct rand *rng, bool store) +{ + u8_t last; + + if (!rng) { + return -ENOBUFS; + } + + last = rng->last + 1; + if (last == rng->count) { + last = 0; + } + + if (last == rng->first) { + /* this condition should not happen, but due to probable race, + * new value could be generated before NRF_RNG task is stopped. + */ + return -ENOBUFS; + } + + if (!store) { + return -EBUSY; + } + + rng->rand[rng->last] = NRF_RNG->VALUE; + rng->last = last; + + last = rng->last + 1; + if (last == rng->count) { + last = 0; + } + + if (last == rng->first) { + return 0; + } + + return -EBUSY; +} + void isr_rand(void *param) { ARG_UNUSED(param); if (NRF_RNG->EVENTS_VALRDY) { - u8_t last; + u8_t ret; - last = rng->last + 1; - if (last == rng->count) { - last = 0; - } - - if (last == rng->first) { - /* this condition should not happen - * , but due to probable bug in HW - * , new value could be generated - * before task is stopped. - */ - NRF_RNG->TASKS_STOP = 1; - NRF_RNG->EVENTS_VALRDY = 0; - - return; - } - - rng->rand[rng->last] = NRF_RNG->VALUE; - rng->last = last; - - last = rng->last + 1; - if (last == rng->count) { - last = 0; + ret = isr(rng_isr, true); + if (ret != -EBUSY) { + ret = isr(rng_thr, (ret == -ENOBUFS)); } NRF_RNG->EVENTS_VALRDY = 0; - if (last == rng->first) { + if (ret != -EBUSY) { NRF_RNG->TASKS_STOP = 1; } } diff --git a/subsys/bluetooth/controller/hal/rand.h b/subsys/bluetooth/controller/hal/rand.h index a09c2dec69a..128edfafc2f 100644 --- a/subsys/bluetooth/controller/hal/rand.h +++ b/subsys/bluetooth/controller/hal/rand.h @@ -8,8 +8,10 @@ #ifndef _RAND_H_ #define _RAND_H_ -void rand_init(u8_t *context, u8_t context_len); +void rand_init(u8_t *context, u8_t context_len, u8_t threshold); +void rand_isr_init(u8_t *context, u8_t context_len, u8_t threshold); size_t rand_get(size_t octets, u8_t *rand); +size_t rand_isr_get(size_t octets, u8_t *rand); void isr_rand(void *param); #endif /* _RAND_H_ */ diff --git a/subsys/bluetooth/controller/ll_sw/ctrl.c b/subsys/bluetooth/controller/ll_sw/ctrl.c index b01b178a1b4..c13389af780 100644 --- a/subsys/bluetooth/controller/ll_sw/ctrl.c +++ b/subsys/bluetooth/controller/ll_sw/ctrl.c @@ -3227,8 +3227,9 @@ static inline u32_t isr_close_adv(void) u32_t ticker_status; u8_t random_delay; - /** @todo use random 0-10 */ - random_delay = 10; + rand_isr_get(sizeof(random_delay), &random_delay); + random_delay %= 10; + random_delay += 1; /* Call to ticker_update can fail under the race * condition where in the Adv role is being stopped but @@ -8095,12 +8096,11 @@ static void enc_req_reused_send(struct connection *conn, conn->llcp.encryption.ediv[0]; pdu_ctrl_tx->payload.llctrl.ctrldata.enc_req.ediv[1] = conn->llcp.encryption.ediv[1]; - /** @todo */ - memset(&pdu_ctrl_tx->payload.llctrl.ctrldata.enc_req.skdm[0], 0xcc, - sizeof(pdu_ctrl_tx->payload.llctrl.ctrldata.enc_req.skdm)); - /** @todo */ - memset(&pdu_ctrl_tx->payload.llctrl.ctrldata.enc_req.ivm[0], 0xdd, - sizeof(pdu_ctrl_tx->payload.llctrl.ctrldata.enc_req.ivm)); + /* NOTE: if not sufficient random numbers, ignore waiting */ + rand_isr_get(sizeof(pdu_ctrl_tx->payload.llctrl.ctrldata.enc_req.skdm), + pdu_ctrl_tx->payload.llctrl.ctrldata.enc_req.skdm); + rand_isr_get(sizeof(pdu_ctrl_tx->payload.llctrl.ctrldata.enc_req.ivm), + pdu_ctrl_tx->payload.llctrl.ctrldata.enc_req.ivm); } static void enc_rsp_send(struct connection *conn) @@ -8117,12 +8117,11 @@ static void enc_rsp_send(struct connection *conn) pdu_ctrl_tx->len = offsetof(struct pdu_data_llctrl, ctrldata) + sizeof(struct pdu_data_llctrl_enc_rsp); pdu_ctrl_tx->payload.llctrl.opcode = PDU_DATA_LLCTRL_TYPE_ENC_RSP; - /** @todo */ - memset(&pdu_ctrl_tx->payload.llctrl.ctrldata.enc_rsp.skds[0], 0xaa, - sizeof(pdu_ctrl_tx->payload.llctrl.ctrldata.enc_rsp.skds)); - /** @todo */ - memset(&pdu_ctrl_tx->payload.llctrl.ctrldata.enc_rsp.ivs[0], 0xbb, - sizeof(pdu_ctrl_tx->payload.llctrl.ctrldata.enc_rsp.ivs)); + /* NOTE: if not sufficient random numbers, ignore waiting */ + rand_isr_get(sizeof(pdu_ctrl_tx->payload.llctrl.ctrldata.enc_rsp.skds), + pdu_ctrl_tx->payload.llctrl.ctrldata.enc_rsp.skds); + rand_isr_get(sizeof(pdu_ctrl_tx->payload.llctrl.ctrldata.enc_rsp.ivs), + pdu_ctrl_tx->payload.llctrl.ctrldata.enc_rsp.ivs); /* things from slave stored for session key calculation */ memcpy(&conn->llcp.encryption.skd[8], @@ -9342,30 +9341,21 @@ u32_t ll_enc_req_send(u16_t handle, u8_t *rand, u8_t *ediv, u8_t *ltk) sizeof(conn->llcp.encryption.ltk)); if ((conn->enc_rx == 0) && (conn->enc_tx == 0)) { + struct pdu_data_llctrl_enc_req *enc_req; + pdu_data_tx->ll_id = PDU_DATA_LLID_CTRL; pdu_data_tx->len = offsetof(struct pdu_data_llctrl, ctrldata) + sizeof(struct pdu_data_llctrl_enc_req); pdu_data_tx->payload.llctrl.opcode = PDU_DATA_LLCTRL_TYPE_ENC_REQ; - memcpy(&pdu_data_tx->payload.llctrl.ctrldata. - enc_req.rand[0], rand, - sizeof(pdu_data_tx->payload.llctrl.ctrldata. - enc_req.rand)); - pdu_data_tx->payload.llctrl.ctrldata.enc_req.ediv[0] = - ediv[0]; - pdu_data_tx->payload.llctrl.ctrldata.enc_req.ediv[1] = - ediv[1]; - memset(&pdu_data_tx->payload.llctrl.ctrldata.enc_req. - skdm[0], 0xcc, - /** @todo */ - sizeof(pdu_data_tx->payload.llctrl.ctrldata. - enc_req.skdm)); - memset(&pdu_data_tx->payload.llctrl.ctrldata.enc_req. - ivm[0], 0xdd, - /** @todo */ - sizeof(pdu_data_tx->payload.llctrl.ctrldata. - enc_req.ivm)); + enc_req = (void *) + &pdu_data_tx->payload.llctrl.ctrldata.enc_req; + memcpy(enc_req->rand, rand, sizeof(enc_req->rand)); + enc_req->ediv[0] = ediv[0]; + enc_req->ediv[1] = ediv[1]; + bt_rand(enc_req->skdm, sizeof(enc_req->skdm)); + bt_rand(enc_req->ivm, sizeof(enc_req->ivm)); } else if ((conn->enc_rx != 0) && (conn->enc_tx != 0)) { memcpy(&conn->llcp.encryption.rand[0], rand, sizeof(conn->llcp.encryption.rand)); diff --git a/subsys/bluetooth/controller/ll_sw/ll.c b/subsys/bluetooth/controller/ll_sw/ll.c index c7a6ba8278b..d3e697a6506 100644 --- a/subsys/bluetooth/controller/ll_sw/ll.c +++ b/subsys/bluetooth/controller/ll_sw/ll.c @@ -41,7 +41,10 @@ /* Global singletons */ /* memory for storing Random number */ -static u8_t MALIGN(4) _rand_context[3 + 4 + 1]; +#define RAND_THREAD_THRESHOLD 4 /* atleast access address */ +#define RAND_ISR_THRESHOLD 12 /* atleast encryption div. and iv */ +static u8_t MALIGN(4) rand_context[4 + RAND_THREAD_THRESHOLD + 1]; +static u8_t MALIGN(4) rand_isr_context[4 + RAND_ISR_THRESHOLD + 1]; #if defined(CONFIG_SOC_FLASH_NRF5_RADIO_SYNC) #define FLASH_TICKER_NODES 1 /* No. of tickers reserved for flashing */ @@ -198,7 +201,9 @@ int ll_init(struct k_sem *sem_rx) sem_recv = sem_rx; /* TODO: bind and use RNG driver */ - rand_init(_rand_context, sizeof(_rand_context)); + rand_init(rand_context, sizeof(rand_context), RAND_THREAD_THRESHOLD); + rand_isr_init(rand_isr_context, sizeof(rand_isr_context), + RAND_ISR_THRESHOLD); clk_k32 = device_get_binding(CONFIG_CLOCK_CONTROL_NRF5_K32SRC_DRV_NAME); if (!clk_k32) {