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