xref: /nrf52832-nimble/packages/NimBLE-latest/nimble/controller/src/ble_ll_rand.c (revision 042d53a763ad75cb1465103098bb88c245d95138)
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