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 <stdint.h>
20 #include <stdio.h>
21 #include <string.h>
22 #include "securec.h"
23 #include "stats/stats.h"
24 #include "ble_hs_priv.h"
25
26 static uint8_t ble_hs_pvcy_started;
27 static uint8_t ble_hs_pvcy_irk[16];
28
29 /** Use this as a default IRK if none gets set. */
30 const uint8_t ble_hs_pvcy_default_irk[16] = {
31 0xef, 0x8d, 0xe2, 0x16, 0x4f, 0xec, 0x43, 0x0d,
32 0xbf, 0x5b, 0xdd, 0x34, 0xc0, 0x53, 0x1e, 0xb8,
33 };
34
ble_hs_pvcy_set_addr_timeout(uint16_t timeout)35 static int ble_hs_pvcy_set_addr_timeout(uint16_t timeout)
36 {
37 struct ble_hci_le_set_rpa_tmo_cp cmd;
38
39 if (timeout == 0 || timeout > 0xA1B8) {
40 return BLE_ERR_INV_HCI_CMD_PARMS;
41 }
42
43 cmd.rpa_timeout = htole16(timeout);
44 return ble_hs_hci_cmd_tx(BLE_HCI_OP(BLE_HCI_OGF_LE,
45 BLE_HCI_OCF_LE_SET_RPA_TMO),
46 &cmd, sizeof(cmd), NULL, 0);
47 }
48
ble_hs_pvcy_set_resolve_enabled(int enable)49 static int ble_hs_pvcy_set_resolve_enabled(int enable)
50 {
51 struct ble_hci_le_set_addr_res_en_cp cmd;
52 cmd.enable = enable;
53 return ble_hs_hci_cmd_tx(BLE_HCI_OP(BLE_HCI_OGF_LE,
54 BLE_HCI_OCF_LE_SET_ADDR_RES_EN),
55 &cmd, sizeof(cmd), NULL, 0);
56 }
57
ble_hs_pvcy_remove_entry(uint8_t addr_type,const uint8_t * addr)58 int ble_hs_pvcy_remove_entry(uint8_t addr_type, const uint8_t *addr)
59 {
60 uint8_t addr_type_tmp = addr_type;
61 struct ble_hci_le_rmv_resolve_list_cp cmd;
62
63 if (addr_type_tmp > BLE_ADDR_RANDOM) {
64 addr_type_tmp = addr_type_tmp % 2; // 2:byte alignment
65 }
66
67 cmd.peer_addr_type = addr_type_tmp;
68 memcpy_s(cmd.peer_id_addr, sizeof(cmd.peer_id_addr), addr, BLE_DEV_ADDR_LEN);
69 return ble_hs_hci_cmd_tx(BLE_HCI_OP(BLE_HCI_OGF_LE,
70 BLE_HCI_OCF_LE_RMV_RESOLV_LIST),
71 &cmd, sizeof(cmd), NULL, 0);
72 }
73
ble_hs_pvcy_clear_entries(void)74 static int ble_hs_pvcy_clear_entries(void)
75 {
76 return ble_hs_hci_cmd_tx(BLE_HCI_OP(BLE_HCI_OGF_LE,
77 BLE_HCI_OCF_LE_CLR_RESOLV_LIST),
78 NULL, 0, NULL, 0);
79 }
80
ble_hs_pvcy_add_entry_hci(const uint8_t * addr,uint8_t addr_type,const uint8_t * irk)81 static int ble_hs_pvcy_add_entry_hci(const uint8_t *addr, uint8_t addr_type, const uint8_t *irk)
82 {
83 struct ble_hci_le_add_resolv_list_cp cmd;
84 ble_addr_t peer_addr;
85 int rc;
86
87 if (addr_type > BLE_ADDR_RANDOM) {
88 return BLE_ERR_INV_HCI_CMD_PARMS;
89 }
90
91 cmd.peer_addr_type = addr_type;
92 memcpy_s(cmd.peer_id_addr, sizeof(cmd.peer_id_addr), addr, 6); // 6:size
93 memcpy_s(cmd.local_irk, sizeof(cmd.local_irk), ble_hs_pvcy_irk, 16); // 16:size
94 memcpy_s(cmd.peer_irk, sizeof(cmd.peer_irk), irk, 16); // 16:size
95 rc = ble_hs_hci_cmd_tx(BLE_HCI_OP(BLE_HCI_OGF_LE,
96 BLE_HCI_OCF_LE_ADD_RESOLV_LIST),
97 &cmd, sizeof(cmd), NULL, 0);
98 if (rc != 0) {
99 return rc;
100 }
101
102 return 0;
103 /* Controller is BT5.0 and default privacy mode is network which
104 * can cause problems for apps which are not aware of it. We need to
105 * sort it out somehow. For now we set device mode for all of the peer
106 * devices and application should change it to network if needed
107 */
108 peer_addr.type = addr_type;
109 memcpy_s(peer_addr.val, sizeof(peer_addr.val), addr, sizeof peer_addr.val);
110 rc = ble_hs_pvcy_set_mode(&peer_addr, BLE_GAP_PRIVATE_MODE_DEVICE);
111 if (rc != 0) {
112 return rc;
113 }
114
115 return 0;
116 }
117
ble_hs_pvcy_add_entry(const uint8_t * addr,uint8_t addr_type,const uint8_t * irk)118 int ble_hs_pvcy_add_entry(const uint8_t *addr, uint8_t addr_type, const uint8_t *irk)
119 {
120 int rc;
121 STATS_INC(ble_hs_stats, pvcy_add_entry);
122 /* No GAP procedures can be active when adding an entry to the resolving
123 * list (Vol 2, Part E, 7.8.38). Stop all GAP procedures and temporarily
124 * prevent any new ones from being started.
125 */
126 ble_gap_preempt();
127 /* Try to add the entry now that GAP is halted. */
128 rc = ble_hs_pvcy_add_entry_hci(addr, addr_type, irk);
129 /* Allow GAP procedures to be started again. */
130 ble_gap_preempt_done();
131
132 if (rc != 0) {
133 STATS_INC(ble_hs_stats, pvcy_add_entry_fail);
134 }
135
136 return rc;
137 }
138
ble_hs_pvcy_ensure_started(void)139 int ble_hs_pvcy_ensure_started(void)
140 {
141 int rc;
142
143 if (ble_hs_pvcy_started) {
144 return 0;
145 }
146
147 /* Set up the periodic change of our RPA. */
148 rc = ble_hs_pvcy_set_addr_timeout(MYNEWT_VAL(BLE_RPA_TIMEOUT));
149 if (rc != 0) {
150 return rc;
151 }
152
153 ble_hs_pvcy_started = 1;
154 return 0;
155 }
156
ble_hs_pvcy_set_our_irk(const uint8_t * irk)157 int ble_hs_pvcy_set_our_irk(const uint8_t *irk)
158 {
159 uint8_t new_irk[16];
160
161 if (irk != NULL) {
162 memcpy_s(new_irk, sizeof(new_irk), irk, 16); // 16:size
163 } else {
164 memcpy_s(new_irk, sizeof(ble_hs_pvcy_default_irk), ble_hs_pvcy_default_irk, 16); // 16:size
165 }
166
167 /* Clear the resolving list if this is a new IRK. */
168 /* Note , the bluetooth system will be automatically on/off, here I always set default local irk and enable rpa */
169 if (1) {
170 memcpy_s(ble_hs_pvcy_irk, sizeof(ble_hs_pvcy_irk), new_irk, 16); // 16:size
171 int rc = ble_hs_pvcy_set_resolve_enabled(0);
172 if (rc != 0) {
173 return rc;
174 }
175
176 rc = ble_hs_pvcy_clear_entries();
177 if (rc != 0) {
178 return rc;
179 }
180
181 rc = ble_hs_pvcy_set_resolve_enabled(1);
182 if (rc != 0) {
183 return rc;
184 }
185
186 /*
187 * Add local IRK entry with 00:00:00:00:00:00 address. This entry will
188 * be used to generate RPA for non-directed advertising if own_addr_type
189 * is set to rpa_pub since we use all-zero address as peer addres in
190 * such case. Peer IRK should be left all-zero since this is not for an
191 * actual peer.
192 */
193 uint8_t tmp_addr[6];
194 memset_s(tmp_addr, sizeof(tmp_addr), 0, 6); // 16:size
195 memset_s(new_irk, sizeof(new_irk), 0, 16); // 16:size
196 rc = ble_hs_pvcy_add_entry(tmp_addr, 0, new_irk);
197 if (rc != 0) {
198 return rc;
199 }
200 }
201
202 return 0;
203 }
204
ble_hs_pvcy_our_irk(const uint8_t ** out_irk)205 int ble_hs_pvcy_our_irk(const uint8_t **out_irk)
206 {
207 /* XXX: Return error if privacy not supported. */
208 *out_irk = ble_hs_pvcy_irk;
209 return 0;
210 }
211
ble_hs_pvcy_set_mode(const ble_addr_t * addr,uint8_t priv_mode)212 int ble_hs_pvcy_set_mode(const ble_addr_t *addr, uint8_t priv_mode)
213 {
214 struct ble_hci_le_set_privacy_mode_cp cmd;
215
216 if (addr->type > BLE_ADDR_RANDOM) {
217 return BLE_ERR_INV_HCI_CMD_PARMS;
218 }
219
220 cmd.mode = priv_mode;
221 cmd.peer_id_addr_type = addr->type;
222 memcpy_s(cmd.peer_id_addr, sizeof(cmd.peer_id_addr), addr->val, BLE_DEV_ADDR_LEN);
223 return ble_hs_hci_cmd_tx(BLE_HCI_OP(BLE_HCI_OGF_LE,
224 BLE_HCI_OCF_LE_SET_PRIVACY_MODE),
225 &cmd, sizeof(cmd), NULL, 0);
226 }