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 "ble/xcvr.h"
26 #include "nimble/ble.h"
27 #include "nimble/nimble_opt.h"
28 #include "nrfx.h"
29 #include "controller/ble_hw.h"
30 #if MYNEWT
31 #include "mcu/cmsis_nvic.h"
32 #else
33 #include "core_cm4.h"
34 #include <nimble/nimble_npl_os.h>
35 #endif
36 #include "os/os_trace_api.h"
37
38 /* Total number of resolving list elements */
39 #define BLE_HW_RESOLV_LIST_SIZE (16)
40
41 /* We use this to keep track of which entries are set to valid addresses */
42 static uint8_t g_ble_hw_whitelist_mask;
43
44 /* Random number generator isr callback */
45 ble_rng_isr_cb_t g_ble_rng_isr_cb;
46
47 /* If LL privacy is enabled, allocate memory for AAR */
48 #if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) == 1)
49
50 /* The NRF51 supports up to 16 IRK entries */
51 #if (MYNEWT_VAL(BLE_LL_RESOLV_LIST_SIZE) < 16)
52 #define NRF_IRK_LIST_ENTRIES (MYNEWT_VAL(BLE_LL_RESOLV_LIST_SIZE))
53 #else
54 #define NRF_IRK_LIST_ENTRIES (16)
55 #endif
56
57 /* NOTE: each entry is 16 bytes long. */
58 uint32_t g_nrf_irk_list[NRF_IRK_LIST_ENTRIES * 4];
59
60 /* Current number of IRK entries */
61 uint8_t g_nrf_num_irks;
62
63 #endif
64
65 /* Returns public device address or -1 if not present */
66 int
ble_hw_get_public_addr(ble_addr_t * addr)67 ble_hw_get_public_addr(ble_addr_t *addr)
68 {
69 int rc;
70 uint32_t addr_high;
71 uint32_t addr_low;
72
73 /* Does FICR have a public address */
74 rc = -1;
75 if ((NRF_FICR->DEVICEADDRTYPE & 1) == 0) {
76 addr_low = NRF_FICR->DEVICEADDR[0];
77 addr_high = NRF_FICR->DEVICEADDR[1];
78 rc = 0;
79 } else {
80 /* See if programmed in UICR. Upper 16 bits must all be zero */
81 addr_high = NRF_UICR->CUSTOMER[1];
82 if (addr_high < 65536) {
83 addr_low = NRF_UICR->CUSTOMER[0];
84 rc = 0;
85 }
86 }
87
88 if (!rc) {
89 /* Copy into device address. We can do this because we know platform */
90 memcpy(addr->val, &addr_low, 4);
91 memcpy(&addr->val[4], &addr_high, 2);
92 addr->type = BLE_ADDR_PUBLIC;
93 }
94
95 return rc;
96 }
97
98 /* Returns random static address or -1 if not present */
99 int
ble_hw_get_static_addr(ble_addr_t * addr)100 ble_hw_get_static_addr(ble_addr_t *addr)
101 {
102 int rc;
103
104 if ((NRF_FICR->DEVICEADDRTYPE & 1) == 1) {
105 memcpy(addr->val, (void *)&NRF_FICR->DEVICEADDR[0], 4);
106 memcpy(&addr->val[4], (void *)&NRF_FICR->DEVICEADDR[1], 2);
107 addr->val[5] |= 0xc0;
108 addr->type = BLE_ADDR_RANDOM;
109 rc = 0;
110 } else {
111 rc = -1;
112 }
113
114 return rc;
115 }
116
117 /**
118 * Clear the whitelist
119 *
120 * @return int
121 */
122 void
ble_hw_whitelist_clear(void)123 ble_hw_whitelist_clear(void)
124 {
125 NRF_RADIO->DACNF = 0;
126 g_ble_hw_whitelist_mask = 0;
127 }
128
129 /**
130 * Add a device to the hw whitelist
131 *
132 * @param addr
133 * @param addr_type
134 *
135 * @return int 0: success, BLE error code otherwise
136 */
137 int
ble_hw_whitelist_add(uint8_t * addr,uint8_t addr_type)138 ble_hw_whitelist_add(uint8_t *addr, uint8_t addr_type)
139 {
140 int i;
141 uint32_t mask;
142
143 /* Find first ununsed device address match element */
144 mask = 0x01;
145 for (i = 0; i < BLE_HW_WHITE_LIST_SIZE; ++i) {
146 if ((mask & g_ble_hw_whitelist_mask) == 0) {
147 NRF_RADIO->DAB[i] = get_le32(addr);
148 NRF_RADIO->DAP[i] = get_le16(addr + 4);
149 if (addr_type == BLE_ADDR_RANDOM) {
150 NRF_RADIO->DACNF |= (mask << 8);
151 }
152 g_ble_hw_whitelist_mask |= mask;
153 return BLE_ERR_SUCCESS;
154 }
155 mask <<= 1;
156 }
157
158 return BLE_ERR_MEM_CAPACITY;
159 }
160
161 /**
162 * Remove a device from the hw whitelist
163 *
164 * @param addr
165 * @param addr_type
166 *
167 */
168 void
ble_hw_whitelist_rmv(uint8_t * addr,uint8_t addr_type)169 ble_hw_whitelist_rmv(uint8_t *addr, uint8_t addr_type)
170 {
171 int i;
172 uint8_t cfg_addr;
173 uint16_t dap;
174 uint16_t txadd;
175 uint32_t dab;
176 uint32_t mask;
177
178 /* Find first ununsed device address match element */
179 dab = get_le32(addr);
180 dap = get_le16(addr + 4);
181 txadd = NRF_RADIO->DACNF >> 8;
182 mask = 0x01;
183 for (i = 0; i < BLE_HW_WHITE_LIST_SIZE; ++i) {
184 if (mask & g_ble_hw_whitelist_mask) {
185 if ((dab == NRF_RADIO->DAB[i]) && (dap == NRF_RADIO->DAP[i])) {
186 cfg_addr = txadd & mask;
187 if (addr_type == BLE_ADDR_RANDOM) {
188 if (cfg_addr != 0) {
189 break;
190 }
191 } else {
192 if (cfg_addr == 0) {
193 break;
194 }
195 }
196 }
197 }
198 mask <<= 1;
199 }
200
201 if (i < BLE_HW_WHITE_LIST_SIZE) {
202 g_ble_hw_whitelist_mask &= ~mask;
203 NRF_RADIO->DACNF &= ~mask;
204 }
205 }
206
207 /**
208 * Returns the size of the whitelist in HW
209 *
210 * @return int Number of devices allowed in whitelist
211 */
212 uint8_t
ble_hw_whitelist_size(void)213 ble_hw_whitelist_size(void)
214 {
215 return BLE_HW_WHITE_LIST_SIZE;
216 }
217
218 /**
219 * Enable the whitelisted devices
220 */
221 void
ble_hw_whitelist_enable(void)222 ble_hw_whitelist_enable(void)
223 {
224 /* Enable the configured device addresses */
225 NRF_RADIO->DACNF |= g_ble_hw_whitelist_mask;
226 }
227
228 /**
229 * Disables the whitelisted devices
230 */
231 void
ble_hw_whitelist_disable(void)232 ble_hw_whitelist_disable(void)
233 {
234 /* Disable all whitelist devices */
235 NRF_RADIO->DACNF &= 0x0000ff00;
236 }
237
238 /**
239 * Boolean function which returns true ('1') if there is a match on the
240 * whitelist.
241 *
242 * @return int
243 */
244 int
ble_hw_whitelist_match(void)245 ble_hw_whitelist_match(void)
246 {
247 return (int)NRF_RADIO->EVENTS_DEVMATCH;
248 }
249
250 /* Encrypt data */
251 int
ble_hw_encrypt_block(struct ble_encryption_block * ecb)252 ble_hw_encrypt_block(struct ble_encryption_block *ecb)
253 {
254 int rc;
255 uint32_t end;
256 uint32_t err;
257
258 /* Stop ECB */
259 NRF_ECB->TASKS_STOPECB = 1;
260 /* XXX: does task stop clear these counters? Anyway to do this quicker? */
261 NRF_ECB->EVENTS_ENDECB = 0;
262 NRF_ECB->EVENTS_ERRORECB = 0;
263 NRF_ECB->ECBDATAPTR = (uint32_t)ecb;
264
265 /* Start ECB */
266 NRF_ECB->TASKS_STARTECB = 1;
267
268 /* Wait till error or done */
269 rc = 0;
270 while (1) {
271 end = NRF_ECB->EVENTS_ENDECB;
272 err = NRF_ECB->EVENTS_ERRORECB;
273 if (end || err) {
274 if (err) {
275 rc = -1;
276 }
277 break;
278 }
279 }
280
281 return rc;
282 }
283
284 /**
285 * Random number generator ISR.
286 */
287 static void
ble_rng_isr(void)288 ble_rng_isr(void)
289 {
290 uint8_t rnum;
291
292 os_trace_isr_enter();
293
294 /* No callback? Clear and disable interrupts */
295 if (g_ble_rng_isr_cb == NULL) {
296 NRF_RNG->INTENCLR = 1;
297 NRF_RNG->EVENTS_VALRDY = 0;
298 (void)NRF_RNG->SHORTS;
299 os_trace_isr_exit();
300 return;
301 }
302
303 /* If there is a value ready grab it */
304 if (NRF_RNG->EVENTS_VALRDY) {
305 NRF_RNG->EVENTS_VALRDY = 0;
306 rnum = (uint8_t)NRF_RNG->VALUE;
307 (*g_ble_rng_isr_cb)(rnum);
308 }
309
310 os_trace_isr_exit();
311 }
312
313 /**
314 * Initialize the random number generator
315 *
316 * @param cb
317 * @param bias
318 *
319 * @return int
320 */
321 int
ble_hw_rng_init(ble_rng_isr_cb_t cb,int bias)322 ble_hw_rng_init(ble_rng_isr_cb_t cb, int bias)
323 {
324 /* Set bias */
325 if (bias) {
326 NRF_RNG->CONFIG = 1;
327 } else {
328 NRF_RNG->CONFIG = 0;
329 }
330
331 /* If we were passed a function pointer we need to enable the interrupt */
332 if (cb != NULL) {
333 NVIC_SetPriority(RNG_IRQn, (1 << __NVIC_PRIO_BITS) - 1);
334 #if MYNEWT
335 NVIC_SetVector(RNG_IRQn, (uint32_t)ble_rng_isr);
336 #else
337 ble_npl_hw_set_isr(RNG_IRQn, ble_rng_isr);
338 #endif
339 NVIC_EnableIRQ(RNG_IRQn);
340 g_ble_rng_isr_cb = cb;
341 }
342
343 return 0;
344 }
345
346 /**
347 * Start the random number generator
348 *
349 * @return int
350 */
351 int
ble_hw_rng_start(void)352 ble_hw_rng_start(void)
353 {
354 os_sr_t sr;
355
356 /* No need for interrupt if there is no callback */
357 OS_ENTER_CRITICAL(sr);
358 NRF_RNG->EVENTS_VALRDY = 0;
359 if (g_ble_rng_isr_cb) {
360 NRF_RNG->INTENSET = 1;
361 }
362 NRF_RNG->TASKS_START = 1;
363 OS_EXIT_CRITICAL(sr);
364
365 return 0;
366 }
367
368 /**
369 * Stop the random generator
370 *
371 * @return int
372 */
373 int
ble_hw_rng_stop(void)374 ble_hw_rng_stop(void)
375 {
376 os_sr_t sr;
377
378 /* No need for interrupt if there is no callback */
379 OS_ENTER_CRITICAL(sr);
380 NRF_RNG->INTENCLR = 1;
381 NRF_RNG->TASKS_STOP = 1;
382 NRF_RNG->EVENTS_VALRDY = 0;
383 OS_EXIT_CRITICAL(sr);
384
385 return 0;
386 }
387
388 /**
389 * Read the random number generator.
390 *
391 * @return uint8_t
392 */
393 uint8_t
ble_hw_rng_read(void)394 ble_hw_rng_read(void)
395 {
396 uint8_t rnum;
397
398 /* Wait for a sample */
399 while (NRF_RNG->EVENTS_VALRDY == 0) {
400 }
401
402 NRF_RNG->EVENTS_VALRDY = 0;
403 rnum = (uint8_t)NRF_RNG->VALUE;
404
405 return rnum;
406 }
407
408 #if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY))
409 /**
410 * Clear the resolving list
411 *
412 * @return int
413 */
414 void
ble_hw_resolv_list_clear(void)415 ble_hw_resolv_list_clear(void)
416 {
417 g_nrf_num_irks = 0;
418 }
419
420 /**
421 * Add a device to the hw resolving list
422 *
423 * @param irk Pointer to IRK to add
424 *
425 * @return int 0: success, BLE error code otherwise
426 */
427 int
ble_hw_resolv_list_add(uint8_t * irk)428 ble_hw_resolv_list_add(uint8_t *irk)
429 {
430 uint32_t *nrf_entry;
431
432 /* Find first ununsed device address match element */
433 if (g_nrf_num_irks == NRF_IRK_LIST_ENTRIES) {
434 return BLE_ERR_MEM_CAPACITY;
435 }
436
437 /* Copy into irk list */
438 nrf_entry = &g_nrf_irk_list[4 * g_nrf_num_irks];
439 memcpy(nrf_entry, irk, 16);
440
441 /* Add to total */
442 ++g_nrf_num_irks;
443 return BLE_ERR_SUCCESS;
444 }
445
446 /**
447 * Remove a device from the hw resolving list
448 *
449 * @param index Index of IRK to remove
450 */
451 void
ble_hw_resolv_list_rmv(int index)452 ble_hw_resolv_list_rmv(int index)
453 {
454 uint32_t *irk_entry;
455
456 if (index < g_nrf_num_irks) {
457 --g_nrf_num_irks;
458 irk_entry = &g_nrf_irk_list[index];
459 if (g_nrf_num_irks > index) {
460 memmove(irk_entry, irk_entry + 4, g_nrf_num_irks - index);
461 }
462 }
463 }
464
465 /**
466 * Returns the size of the resolving list. NOTE: this returns the maximum
467 * allowable entries in the HW. Configuration options may limit this.
468 *
469 * @return int Number of devices allowed in resolving list
470 */
471 uint8_t
ble_hw_resolv_list_size(void)472 ble_hw_resolv_list_size(void)
473 {
474 return BLE_HW_RESOLV_LIST_SIZE;
475 }
476
477 /**
478 * Called to determine if the address received was resolved.
479 *
480 * @return int Negative values indicate unresolved address; positive values
481 * indicate index in resolving list of resolved address.
482 */
483 int
ble_hw_resolv_list_match(void)484 ble_hw_resolv_list_match(void)
485 {
486 uint32_t index;
487
488 if (NRF_AAR->EVENTS_END) {
489 if (NRF_AAR->EVENTS_RESOLVED) {
490 index = NRF_AAR->STATUS;
491 return (int)index;
492 }
493 }
494
495 return -1;
496 }
497 #endif
498