1*042d53a7SEvalZero /*
2*042d53a7SEvalZero * Licensed to the Apache Software Foundation (ASF) under one
3*042d53a7SEvalZero * or more contributor license agreements. See the NOTICE file
4*042d53a7SEvalZero * distributed with this work for additional information
5*042d53a7SEvalZero * regarding copyright ownership. The ASF licenses this file
6*042d53a7SEvalZero * to you under the Apache License, Version 2.0 (the
7*042d53a7SEvalZero * "License"); you may not use this file except in compliance
8*042d53a7SEvalZero * with the License. You may obtain a copy of the License at
9*042d53a7SEvalZero *
10*042d53a7SEvalZero * http://www.apache.org/licenses/LICENSE-2.0
11*042d53a7SEvalZero *
12*042d53a7SEvalZero * Unless required by applicable law or agreed to in writing,
13*042d53a7SEvalZero * software distributed under the License is distributed on an
14*042d53a7SEvalZero * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15*042d53a7SEvalZero * KIND, either express or implied. See the License for the
16*042d53a7SEvalZero * specific language governing permissions and limitations
17*042d53a7SEvalZero * under the License.
18*042d53a7SEvalZero */
19*042d53a7SEvalZero
20*042d53a7SEvalZero #include <stdint.h>
21*042d53a7SEvalZero #include <assert.h>
22*042d53a7SEvalZero #include <string.h>
23*042d53a7SEvalZero #include "syscfg/syscfg.h"
24*042d53a7SEvalZero #include "os/os.h"
25*042d53a7SEvalZero #include "nimble/ble.h"
26*042d53a7SEvalZero #include "nimble/nimble_opt.h"
27*042d53a7SEvalZero #include "controller/ble_hw.h"
28*042d53a7SEvalZero #include "controller/ble_ll.h"
29*042d53a7SEvalZero #if MYNEWT_VAL(TRNG)
30*042d53a7SEvalZero #include "trng/trng.h"
31*042d53a7SEvalZero #endif
32*042d53a7SEvalZero
33*042d53a7SEvalZero #if MYNEWT_VAL(TRNG)
34*042d53a7SEvalZero static struct trng_dev *g_trng;
35*042d53a7SEvalZero #else
36*042d53a7SEvalZero /* This is a simple circular buffer for holding N samples of random data */
37*042d53a7SEvalZero struct ble_ll_rnum_data
38*042d53a7SEvalZero {
39*042d53a7SEvalZero uint8_t *rnd_in;
40*042d53a7SEvalZero uint8_t *rnd_out;
41*042d53a7SEvalZero volatile uint8_t rnd_size;
42*042d53a7SEvalZero };
43*042d53a7SEvalZero
44*042d53a7SEvalZero struct ble_ll_rnum_data g_ble_ll_rnum_data;
45*042d53a7SEvalZero uint8_t g_ble_ll_rnum_buf[MYNEWT_VAL(BLE_LL_RNG_BUFSIZE)];
46*042d53a7SEvalZero
47*042d53a7SEvalZero #define IS_RNUM_BUF_END(x) \
48*042d53a7SEvalZero (x == &g_ble_ll_rnum_buf[MYNEWT_VAL(BLE_LL_RNG_BUFSIZE) - 1])
49*042d53a7SEvalZero
50*042d53a7SEvalZero void
ble_ll_rand_sample(uint8_t rnum)51*042d53a7SEvalZero ble_ll_rand_sample(uint8_t rnum)
52*042d53a7SEvalZero {
53*042d53a7SEvalZero os_sr_t sr;
54*042d53a7SEvalZero
55*042d53a7SEvalZero OS_ENTER_CRITICAL(sr);
56*042d53a7SEvalZero if (g_ble_ll_rnum_data.rnd_size < MYNEWT_VAL(BLE_LL_RNG_BUFSIZE)) {
57*042d53a7SEvalZero ++g_ble_ll_rnum_data.rnd_size;
58*042d53a7SEvalZero g_ble_ll_rnum_data.rnd_in[0] = rnum;
59*042d53a7SEvalZero if (IS_RNUM_BUF_END(g_ble_ll_rnum_data.rnd_in)) {
60*042d53a7SEvalZero g_ble_ll_rnum_data.rnd_in = g_ble_ll_rnum_buf;
61*042d53a7SEvalZero } else {
62*042d53a7SEvalZero ++g_ble_ll_rnum_data.rnd_in;
63*042d53a7SEvalZero }
64*042d53a7SEvalZero } else {
65*042d53a7SEvalZero /* Stop generating random numbers as we are full */
66*042d53a7SEvalZero ble_hw_rng_stop();
67*042d53a7SEvalZero }
68*042d53a7SEvalZero OS_EXIT_CRITICAL(sr);
69*042d53a7SEvalZero }
70*042d53a7SEvalZero #endif
71*042d53a7SEvalZero
72*042d53a7SEvalZero /* Get 'len' bytes of random data */
73*042d53a7SEvalZero int
ble_ll_rand_data_get(uint8_t * buf,uint8_t len)74*042d53a7SEvalZero ble_ll_rand_data_get(uint8_t *buf, uint8_t len)
75*042d53a7SEvalZero {
76*042d53a7SEvalZero #if MYNEWT_VAL(TRNG)
77*042d53a7SEvalZero size_t num;
78*042d53a7SEvalZero
79*042d53a7SEvalZero while (len) {
80*042d53a7SEvalZero num = trng_read(g_trng, buf, len);
81*042d53a7SEvalZero buf += num;
82*042d53a7SEvalZero len -= num;
83*042d53a7SEvalZero }
84*042d53a7SEvalZero #else
85*042d53a7SEvalZero uint8_t rnums;
86*042d53a7SEvalZero os_sr_t sr;
87*042d53a7SEvalZero
88*042d53a7SEvalZero while (len != 0) {
89*042d53a7SEvalZero OS_ENTER_CRITICAL(sr);
90*042d53a7SEvalZero rnums = g_ble_ll_rnum_data.rnd_size;
91*042d53a7SEvalZero if (rnums > len) {
92*042d53a7SEvalZero rnums = len;
93*042d53a7SEvalZero }
94*042d53a7SEvalZero len -= rnums;
95*042d53a7SEvalZero g_ble_ll_rnum_data.rnd_size -= rnums;
96*042d53a7SEvalZero while (rnums) {
97*042d53a7SEvalZero buf[0] = g_ble_ll_rnum_data.rnd_out[0];
98*042d53a7SEvalZero if (IS_RNUM_BUF_END(g_ble_ll_rnum_data.rnd_out)) {
99*042d53a7SEvalZero g_ble_ll_rnum_data.rnd_out = g_ble_ll_rnum_buf;
100*042d53a7SEvalZero } else {
101*042d53a7SEvalZero ++g_ble_ll_rnum_data.rnd_out;
102*042d53a7SEvalZero }
103*042d53a7SEvalZero ++buf;
104*042d53a7SEvalZero --rnums;
105*042d53a7SEvalZero }
106*042d53a7SEvalZero OS_EXIT_CRITICAL(sr);
107*042d53a7SEvalZero
108*042d53a7SEvalZero /* Make sure rng is started! */
109*042d53a7SEvalZero ble_hw_rng_start();
110*042d53a7SEvalZero
111*042d53a7SEvalZero /* Wait till bytes are in buffer. */
112*042d53a7SEvalZero if (len) {
113*042d53a7SEvalZero while ((g_ble_ll_rnum_data.rnd_size < len) &&
114*042d53a7SEvalZero (g_ble_ll_rnum_data.rnd_size < MYNEWT_VAL(BLE_LL_RNG_BUFSIZE))) {
115*042d53a7SEvalZero /* Spin here */
116*042d53a7SEvalZero }
117*042d53a7SEvalZero }
118*042d53a7SEvalZero }
119*042d53a7SEvalZero #endif
120*042d53a7SEvalZero return BLE_ERR_SUCCESS;
121*042d53a7SEvalZero }
122*042d53a7SEvalZero
123*042d53a7SEvalZero /**
124*042d53a7SEvalZero * Called to obtain a "prand" as defined in core V4.2 Vol 6 Part B 1.3.2.2
125*042d53a7SEvalZero *
126*042d53a7SEvalZero * @param prand
127*042d53a7SEvalZero */
128*042d53a7SEvalZero void
ble_ll_rand_prand_get(uint8_t * prand)129*042d53a7SEvalZero ble_ll_rand_prand_get(uint8_t *prand)
130*042d53a7SEvalZero {
131*042d53a7SEvalZero uint16_t sum;
132*042d53a7SEvalZero
133*042d53a7SEvalZero while (1) {
134*042d53a7SEvalZero /* Get 24 bits of random data */
135*042d53a7SEvalZero ble_ll_rand_data_get(prand, 3);
136*042d53a7SEvalZero
137*042d53a7SEvalZero /* Prand cannot be all zeros or 1's. */
138*042d53a7SEvalZero sum = prand[0] + prand[1] + prand[2];
139*042d53a7SEvalZero if ((sum != 0) && (sum != (3 * 0xff))) {
140*042d53a7SEvalZero break;
141*042d53a7SEvalZero }
142*042d53a7SEvalZero }
143*042d53a7SEvalZero
144*042d53a7SEvalZero /* Upper two bits must be 01 */
145*042d53a7SEvalZero prand[2] &= ~0xc0;
146*042d53a7SEvalZero prand[2] |= 0x40;
147*042d53a7SEvalZero }
148*042d53a7SEvalZero
149*042d53a7SEvalZero /**
150*042d53a7SEvalZero * Start the generation of random numbers
151*042d53a7SEvalZero *
152*042d53a7SEvalZero * @return int
153*042d53a7SEvalZero */
154*042d53a7SEvalZero int
ble_ll_rand_start(void)155*042d53a7SEvalZero ble_ll_rand_start(void)
156*042d53a7SEvalZero {
157*042d53a7SEvalZero #if MYNEWT_VAL(TRNG)
158*042d53a7SEvalZero /* Nothing to do - this is handled by driver */
159*042d53a7SEvalZero #else
160*042d53a7SEvalZero /* Start the generation of numbers if we are not full */
161*042d53a7SEvalZero if (g_ble_ll_rnum_data.rnd_size < MYNEWT_VAL(BLE_LL_RNG_BUFSIZE)) {
162*042d53a7SEvalZero ble_hw_rng_start();
163*042d53a7SEvalZero }
164*042d53a7SEvalZero #endif
165*042d53a7SEvalZero return 0;
166*042d53a7SEvalZero }
167*042d53a7SEvalZero
168*042d53a7SEvalZero /**
169*042d53a7SEvalZero * Initialize LL random number generation. Should be called only once on
170*042d53a7SEvalZero * initialization.
171*042d53a7SEvalZero *
172*042d53a7SEvalZero * @return int
173*042d53a7SEvalZero */
174*042d53a7SEvalZero int
ble_ll_rand_init(void)175*042d53a7SEvalZero ble_ll_rand_init(void)
176*042d53a7SEvalZero {
177*042d53a7SEvalZero #if MYNEWT_VAL(TRNG)
178*042d53a7SEvalZero g_trng = (struct trng_dev *) os_dev_open("trng", OS_TIMEOUT_NEVER, NULL);
179*042d53a7SEvalZero #else
180*042d53a7SEvalZero g_ble_ll_rnum_data.rnd_in = g_ble_ll_rnum_buf;
181*042d53a7SEvalZero g_ble_ll_rnum_data.rnd_out = g_ble_ll_rnum_buf;
182*042d53a7SEvalZero ble_hw_rng_init(ble_ll_rand_sample, 1);
183*042d53a7SEvalZero #endif
184*042d53a7SEvalZero return 0;
185*042d53a7SEvalZero }
186