1 /*
2 * Copyright (c) 2017 Oticon A/S
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6 /**
7 * AR — Accelerated address resolver
8 * http://infocenter.nordicsemi.com/topic/com.nordic.infocenter.nrf52840.ps/aar.html?cp=2_0_0_28#frontpage_aar
9 */
10 #include "NRF_AAR.h"
11 #include <string.h>
12 #include <stdbool.h>
13 #include "time_machine_if.h"
14 #include "NRF_HW_model_top.h"
15 #include "NRF_PPI.h"
16 #include "irq_ctrl.h"
17 #include "irq_sources.h"
18 #include "bs_tracing.h"
19 #include "BLECrypt_if.h"
20
21 bs_time_t Timer_AAR = TIME_NEVER; /* Time when the AAR will finish */
22
23 NRF_AAR_Type NRF_AAR_regs;
24 static uint32_t AAR_INTEN = 0; //interrupt enable
25 static bool AAR_Running;
26 static int matching_irk;
27
nrf_aar_init()28 void nrf_aar_init(){
29 memset(&NRF_AAR_regs, 0, sizeof(NRF_AAR_regs));
30 AAR_INTEN = 0;
31 Timer_AAR = TIME_NEVER;
32 AAR_Running = false;
33 }
34
nrf_aar_clean_up()35 void nrf_aar_clean_up(){
36
37 }
38
39 static int nrf_aar_resolve(int *good_irk);
40
signal_EVENTS_END()41 static void signal_EVENTS_END(){
42 NRF_AAR_regs.EVENTS_END = 1;
43 nrf_ppi_event(AAR_EVENTS_END);
44
45 if (AAR_INTEN & AAR_INTENSET_END_Msk){
46 hw_irq_ctrl_set_irq(NRF5_IRQ_CCM_AAR_IRQn);
47 }
48 }
49
signal_EVENTS_RESOLVED()50 static void signal_EVENTS_RESOLVED(){
51 NRF_AAR_regs.EVENTS_RESOLVED = 1;
52 nrf_ppi_event(AAR_EVENTS_RESOLVED);
53
54 if (AAR_INTEN & AAR_INTENCLR_RESOLVED_Msk){
55 hw_irq_ctrl_set_irq(NRF5_IRQ_CCM_AAR_IRQn);
56 }
57 }
58
signal_EVENTS_NOTRESOLVED()59 static void signal_EVENTS_NOTRESOLVED(){
60 NRF_AAR_regs.EVENTS_NOTRESOLVED = 1;
61 nrf_ppi_event(AAR_EVENTS_NOTRESOLVED);
62
63 if (AAR_INTEN & AAR_INTENCLR_NOTRESOLVED_Msk){
64 hw_irq_ctrl_set_irq(NRF5_IRQ_CCM_AAR_IRQn);
65 }
66 }
67
nrf_aar_TASK_START()68 void nrf_aar_TASK_START(){
69 int n_irks;
70
71 if (NRF_AAR_regs.ENABLE != 0x3) {
72 return;
73 }
74
75 AAR_Running = true;
76 n_irks = nrf_aar_resolve(&matching_irk);
77
78 Timer_AAR = tm_get_hw_time() + 1 + 6 * n_irks; /*AAR delay*/
79 nrf_hw_find_next_timer_to_trigger();
80 }
81
nrf_aar_TASK_STOP()82 void nrf_aar_TASK_STOP(){
83 if (!AAR_Running) {
84 return;
85 }
86
87 AAR_Running = false;
88 Timer_AAR = TIME_NEVER;
89 nrf_hw_find_next_timer_to_trigger();
90 signal_EVENTS_END();
91 //Does this actually signal an END?
92 //and only an END?
93 }
94
nrf_aar_regw_sideeffects_INTENSET()95 void nrf_aar_regw_sideeffects_INTENSET(){
96 if ( NRF_AAR_regs.INTENSET ){
97 AAR_INTEN |= NRF_AAR_regs.INTENSET;
98 NRF_AAR_regs.INTENSET = AAR_INTEN;
99 }
100 }
101
nrf_aar_regw_sideeffects_INTENCLR()102 void nrf_aar_regw_sideeffects_INTENCLR(){
103 if ( NRF_AAR_regs.INTENCLR ){
104 AAR_INTEN &= ~NRF_AAR_regs.INTENCLR;
105 NRF_AAR_regs.INTENSET = AAR_INTEN;
106 NRF_AAR_regs.INTENCLR = 0;
107 }
108 }
109
nrf_aar_regw_sideeffects_TASKS_START()110 void nrf_aar_regw_sideeffects_TASKS_START(){
111 if ( NRF_AAR_regs.TASKS_START ) {
112 NRF_AAR_regs.TASKS_START = 0;
113 nrf_aar_TASK_START();
114 }
115 }
116
nrf_aar_regw_sideeffects_TASKS_STOP()117 void nrf_aar_regw_sideeffects_TASKS_STOP(){
118 if ( NRF_AAR_regs.TASKS_STOP ) {
119 NRF_AAR_regs.TASKS_STOP = 0;
120 nrf_aar_TASK_STOP();
121 }
122 }
123
nrf_aar_timer_triggered()124 void nrf_aar_timer_triggered(){
125 AAR_Running = false;
126 Timer_AAR = TIME_NEVER;
127 nrf_hw_find_next_timer_to_trigger();
128
129 if (matching_irk != -1) {
130 NRF_AAR_regs.STATUS = matching_irk;
131 signal_EVENTS_RESOLVED();
132 } else {
133 signal_EVENTS_NOTRESOLVED();
134 }
135 signal_EVENTS_END();
136 }
137
138 /**
139 * Try to resolve the address
140 * Returns the number of IRKs it went thru before matching
141 * (or if it did not, it returns NRF_AAR_regs.NIRK)
142 *
143 * It sets *good_irk to the index of the IRK that matched
144 * or to -1 if none did.
145 */
nrf_aar_resolve(int * good_irk)146 static int nrf_aar_resolve(int *good_irk) {
147 int i;
148 uint8_t prand_buf[16];
149 uint8_t hash_check_buf[16];
150 uint32_t hash, hash_check;
151 uint32_t prand;
152 const uint8_t *irkptr;
153 /*
154 * The AAR module always assumes the S0+Length+S1 occupy 3 bytes
155 * independently of the RADIO config
156 */
157 uint8_t *address_ptr = (uint8_t*)NRF_AAR_regs.ADDRPTR + 3;
158
159 *good_irk = -1;
160
161 bs_trace_raw_time(9,"HW AAR address to match %02x:%02x:%02x:%02x:%02x:%02x\n",
162 address_ptr[5], address_ptr[4], address_ptr[3],
163 address_ptr[2], address_ptr[1], address_ptr[0]);
164
165 prand = *(uint32_t*)(address_ptr+3) & 0xFFFFFF;
166 if (prand >> 22 != 0x01){
167 /* Not a resolvable private address */
168 bs_trace_raw_time(7,"HW AAR the address is not resolvable (0x%06X , %x)\n", prand, prand >> 22);
169 return NRF_AAR_regs.NIRK;
170 }
171
172 memset(prand_buf,0,16);
173
174 /* Endiannes reversal to bigendian */
175 prand_buf[15] = prand & 0xFF;
176 prand_buf[14] = (prand >> 8) & 0xFF;
177 prand_buf[13] = (prand >> 16) & 0xFF;
178
179 for (i = 0 ; i < NRF_AAR_regs.NIRK; i++){
180 /* The provided IRKs are assumed to be already big endian */
181 irkptr = ((const uint8_t*)NRF_AAR_regs.IRKPTR) + 16*i;
182
183 /* this aes_128 function takes and produces big endian results */
184 BLECrypt_if_aes_128(
185 irkptr,
186 prand_buf,
187 hash_check_buf);
188
189 /* Endianess reversal to little endian */
190 hash_check = hash_check_buf[15] | (uint32_t)hash_check_buf[14] << 8 | (uint32_t)hash_check_buf[13] << 16;
191
192 hash = *(uint32_t*)address_ptr & 0xFFFFFF;
193
194 bs_trace_raw_time(9,"HW AAR (%i): checking prand = 0x%06X, hash = 0x%06X, hashcheck = 0x%06X\n",i, prand, hash, hash_check);
195
196 if (hash == hash_check) {
197 bs_trace_raw_time(7,"HW AAR matched irk %i (of %i)\n",i, NRF_AAR_regs.NIRK);
198 *good_irk = i;
199 return i+1;
200 }
201 }
202
203 bs_trace_raw_time(7,"HW AAR did not match any IRK of %i\n", NRF_AAR_regs.NIRK);
204 return i;
205 }
206