xref: /nrf52832-nimble/packages/NimBLE-latest/nimble/host/src/ble_hs_pvcy.c (revision 042d53a763ad75cb1465103098bb88c245d95138)
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 #include <inttypes.h>
20 #include <stdio.h>
21 #include <string.h>
22 #include "stats/stats.h"
23 #include "ble_hs_priv.h"
24 
25 static uint8_t ble_hs_pvcy_started;
26 static uint8_t ble_hs_pvcy_irk[16];
27 
28 /** Use this as a default IRK if none gets set. */
29 const uint8_t ble_hs_pvcy_default_irk[16] = {
30     0xef, 0x8d, 0xe2, 0x16, 0x4f, 0xec, 0x43, 0x0d,
31     0xbf, 0x5b, 0xdd, 0x34, 0xc0, 0x53, 0x1e, 0xb8,
32 };
33 
34 static int
ble_hs_pvcy_set_addr_timeout(uint16_t timeout)35 ble_hs_pvcy_set_addr_timeout(uint16_t timeout)
36 {
37     uint8_t buf[BLE_HCI_SET_RESOLV_PRIV_ADDR_TO_LEN];
38     int rc;
39 
40     rc = ble_hs_hci_cmd_build_set_resolv_priv_addr_timeout(timeout, buf,
41                                                            sizeof(buf));
42     if (rc != 0) {
43         return rc;
44     }
45 
46     return ble_hs_hci_cmd_tx(BLE_HCI_OP(BLE_HCI_OGF_LE,
47                                         BLE_HCI_OCF_LE_SET_RPA_TMO),
48                              buf, sizeof(buf), NULL, 0, NULL);
49 }
50 
51 static int
ble_hs_pvcy_set_resolve_enabled(int enable)52 ble_hs_pvcy_set_resolve_enabled(int enable)
53 {
54     uint8_t buf[BLE_HCI_SET_ADDR_RESOL_ENA_LEN];
55     int rc;
56 
57     rc = ble_hs_hci_cmd_build_set_addr_res_en(enable, buf, sizeof(buf));
58     if (rc != 0) {
59         return rc;
60     }
61 
62     rc = ble_hs_hci_cmd_tx(BLE_HCI_OP(BLE_HCI_OGF_LE,
63                                       BLE_HCI_OCF_LE_SET_ADDR_RES_EN),
64                            buf, sizeof(buf), NULL, 0, NULL);
65     if (rc != 0) {
66         return rc;
67     }
68 
69     return 0;
70 }
71 
72 int
ble_hs_pvcy_remove_entry(uint8_t addr_type,const uint8_t * addr)73 ble_hs_pvcy_remove_entry(uint8_t addr_type, const uint8_t *addr)
74 {
75     uint8_t buf[BLE_HCI_RMV_FROM_RESOLV_LIST_LEN];
76     int rc;
77 
78     rc = ble_hs_hci_cmd_build_remove_from_resolv_list(addr_type, addr,
79                                                       buf, sizeof(buf));
80     if (rc != 0) {
81         return rc;
82     }
83 
84     rc = ble_hs_hci_cmd_tx(BLE_HCI_OP(BLE_HCI_OGF_LE,
85                                       BLE_HCI_OCF_LE_RMV_RESOLV_LIST),
86                            buf, sizeof(buf), NULL, 0, NULL);
87     if (rc != 0) {
88         return rc;
89     }
90 
91     return 0;
92 }
93 
94 static int
ble_hs_pvcy_clear_entries(void)95 ble_hs_pvcy_clear_entries(void)
96 {
97     int rc;
98 
99     rc = ble_hs_hci_cmd_tx(BLE_HCI_OP(BLE_HCI_OGF_LE,
100                                       BLE_HCI_OCF_LE_CLR_RESOLV_LIST),
101                            NULL, 0, NULL, 0, NULL);
102     if (rc != 0) {
103         return rc;
104     }
105 
106     return 0;
107 }
108 
109 static int
ble_hs_pvcy_add_entry_hci(const uint8_t * addr,uint8_t addr_type,const uint8_t * irk)110 ble_hs_pvcy_add_entry_hci(const uint8_t *addr, uint8_t addr_type,
111                           const uint8_t *irk)
112 {
113     struct hci_add_dev_to_resolving_list add;
114     uint8_t buf[BLE_HCI_ADD_TO_RESOLV_LIST_LEN];
115     ble_addr_t peer_addr;
116     int rc;
117 
118     add.addr_type = addr_type;
119     memcpy(add.addr, addr, 6);
120     memcpy(add.local_irk, ble_hs_pvcy_irk, 16);
121     memcpy(add.peer_irk, irk, 16);
122 
123     rc = ble_hs_hci_cmd_build_add_to_resolv_list(&add, buf, sizeof(buf));
124     if (rc != 0) {
125         return rc;
126     }
127 
128     rc = ble_hs_hci_cmd_tx(BLE_HCI_OP(BLE_HCI_OGF_LE,
129                                       BLE_HCI_OCF_LE_ADD_RESOLV_LIST),
130                            buf, sizeof(buf), NULL, 0, NULL);
131     if (rc != 0) {
132         return rc;
133     }
134 
135 
136     /* FIXME Controller is BT5.0 and default privacy mode is network which
137      * can cause problems for apps which are not aware of it. We need to
138      * sort it out somehow. For now we set device mode for all of the peer
139      * devices and application should change it to network if needed
140      */
141     peer_addr.type = addr_type;
142     memcpy(peer_addr.val, addr, sizeof peer_addr.val);
143     rc = ble_hs_pvcy_set_mode(&peer_addr, BLE_GAP_PRIVATE_MODE_DEVICE);
144     if (rc != 0) {
145         return rc;
146     }
147 
148     return 0;
149 }
150 
151 int
ble_hs_pvcy_add_entry(const uint8_t * addr,uint8_t addr_type,const uint8_t * irk)152 ble_hs_pvcy_add_entry(const uint8_t *addr, uint8_t addr_type,
153                       const uint8_t *irk)
154 {
155     int rc;
156 
157     STATS_INC(ble_hs_stats, pvcy_add_entry);
158 
159     /* No GAP procedures can be active when adding an entry to the resolving
160      * list (Vol 2, Part E, 7.8.38).  Stop all GAP procedures and temporarily
161      * prevent any new ones from being started.
162      */
163     ble_gap_preempt();
164 
165     /* Try to add the entry now that GAP is halted. */
166     rc = ble_hs_pvcy_add_entry_hci(addr, addr_type, irk);
167 
168     /* Allow GAP procedures to be started again. */
169     ble_gap_preempt_done();
170 
171     if (rc != 0) {
172         STATS_INC(ble_hs_stats, pvcy_add_entry_fail);
173     }
174 
175     return rc;
176 }
177 
178 int
ble_hs_pvcy_ensure_started(void)179 ble_hs_pvcy_ensure_started(void)
180 {
181     int rc;
182 
183     if (ble_hs_pvcy_started) {
184         return 0;
185     }
186 
187     /* Set up the periodic change of our RPA. */
188     rc = ble_hs_pvcy_set_addr_timeout(MYNEWT_VAL(BLE_RPA_TIMEOUT));
189     if (rc != 0) {
190         return rc;
191     }
192 
193     ble_hs_pvcy_started = 1;
194 
195     return 0;
196 }
197 
198 int
ble_hs_pvcy_set_our_irk(const uint8_t * irk)199 ble_hs_pvcy_set_our_irk(const uint8_t *irk)
200 {
201     uint8_t tmp_addr[6];
202     uint8_t new_irk[16];
203     int rc;
204 
205     if (irk != NULL) {
206         memcpy(new_irk, irk, 16);
207     } else {
208         memcpy(new_irk, ble_hs_pvcy_default_irk, 16);
209     }
210 
211     /* Clear the resolving list if this is a new IRK. */
212     if (memcmp(ble_hs_pvcy_irk, new_irk, 16) != 0) {
213         memcpy(ble_hs_pvcy_irk, new_irk, 16);
214 
215         rc = ble_hs_pvcy_set_resolve_enabled(0);
216         if (rc != 0) {
217             return rc;
218         }
219 
220         rc = ble_hs_pvcy_clear_entries();
221         if (rc != 0) {
222             return rc;
223         }
224 
225         rc = ble_hs_pvcy_set_resolve_enabled(1);
226         if (rc != 0) {
227             return rc;
228         }
229 
230         /*
231          * Add local IRK entry with 00:00:00:00:00:00 address. This entry will
232          * be used to generate RPA for non-directed advertising if own_addr_type
233          * is set to rpa_pub since we use all-zero address as peer addres in
234          * such case. Peer IRK should be left all-zero since this is not for an
235          * actual peer.
236          */
237         memset(tmp_addr, 0, 6);
238         memset(new_irk, 0, 16);
239         rc = ble_hs_pvcy_add_entry(tmp_addr, 0, new_irk);
240         if (rc != 0) {
241             return rc;
242         }
243     }
244 
245     return 0;
246 }
247 
248 int
ble_hs_pvcy_our_irk(const uint8_t ** out_irk)249 ble_hs_pvcy_our_irk(const uint8_t **out_irk)
250 {
251     /* XXX: Return error if privacy not supported. */
252 
253     *out_irk = ble_hs_pvcy_irk;
254     return 0;
255 }
256 
257 int
ble_hs_pvcy_set_mode(const ble_addr_t * addr,uint8_t priv_mode)258 ble_hs_pvcy_set_mode(const ble_addr_t *addr, uint8_t priv_mode)
259 {
260     uint8_t buf[BLE_HCI_LE_SET_PRIVACY_MODE_LEN];
261     int rc;
262 
263     rc = ble_hs_hci_cmd_build_le_set_priv_mode(addr->val, addr->type, priv_mode,
264                                            buf, sizeof(buf));
265     if (rc != 0) {
266         return rc;
267     }
268 
269     return ble_hs_hci_cmd_tx(BLE_HCI_OP(BLE_HCI_OGF_LE,
270                                         BLE_HCI_OCF_LE_SET_PRIVACY_MODE),
271                              buf, sizeof(buf), NULL, 0, NULL);
272 }
273