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