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 <vich@nordicsemi.no>
This commit is contained in:
Vinayak Kariappa Chettimada 2017-08-07 12:12:39 +02:00 committed by Johan Hedberg
commit d90095b556
4 changed files with 126 additions and 86 deletions

View file

@ -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;
}
}

View file

@ -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_ */

View file

@ -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));

View file

@ -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) {