• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 }