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 <assert.h>
21 #include <string.h>
22 #include "syscfg/syscfg.h"
23 #include "os/os.h"
24 #include "nimble/ble.h"
25 #include "nimble/nimble_opt.h"
26 #include "ble/xcvr.h"
27 #include "controller/ble_ll_whitelist.h"
28 #include "controller/ble_ll_hci.h"
29 #include "controller/ble_ll_adv.h"
30 #include "controller/ble_ll_scan.h"
31 #include "controller/ble_hw.h"
32
33 #if (MYNEWT_VAL(BLE_LL_WHITELIST_SIZE) < BLE_HW_WHITE_LIST_SIZE)
34 #define BLE_LL_WHITELIST_SIZE MYNEWT_VAL(BLE_LL_WHITELIST_SIZE)
35 #else
36 #define BLE_LL_WHITELIST_SIZE BLE_HW_WHITE_LIST_SIZE
37 #endif
38
39 struct ble_ll_whitelist_entry
40 {
41 uint8_t wl_valid;
42 uint8_t wl_addr_type;
43 uint8_t wl_dev_addr[BLE_DEV_ADDR_LEN];
44 };
45
46 struct ble_ll_whitelist_entry g_ble_ll_whitelist[BLE_LL_WHITELIST_SIZE];
47
48 static int
ble_ll_whitelist_chg_allowed(void)49 ble_ll_whitelist_chg_allowed(void)
50 {
51 int rc;
52
53 /*
54 * This command is not allowed if:
55 * -> advertising uses the whitelist and we are currently advertising.
56 * -> scanning uses the whitelist and is enabled.
57 * -> initiating uses whitelist and a LE create connection command is in
58 * progress
59 */
60 rc = 1;
61 if (!ble_ll_adv_can_chg_whitelist() || !ble_ll_scan_can_chg_whitelist()) {
62 rc = 0;
63 }
64 return rc;
65 }
66
67 /**
68 * Clear the whitelist.
69 *
70 * @return int 0: success, BLE error code otherwise
71 */
72 int
ble_ll_whitelist_clear(void)73 ble_ll_whitelist_clear(void)
74 {
75 int i;
76 struct ble_ll_whitelist_entry *wl;
77
78 /* Check proper state */
79 if (!ble_ll_whitelist_chg_allowed()) {
80 return BLE_ERR_CMD_DISALLOWED;
81 }
82
83 /* Set the number of entries to 0 */
84 wl = &g_ble_ll_whitelist[0];
85 for (i = 0; i < BLE_LL_WHITELIST_SIZE; ++i) {
86 wl->wl_valid = 0;
87 ++wl;
88 }
89
90 #if (BLE_USES_HW_WHITELIST == 1)
91 ble_hw_whitelist_clear();
92 #endif
93
94 return BLE_ERR_SUCCESS;
95 }
96
97 /**
98 * Read the size of the whitelist. This is the total number of whitelist
99 * entries allowed by the controller.
100 *
101 * @param rspbuf Pointer to response buffer
102 *
103 * @return int 0: success.
104 */
105 int
ble_ll_whitelist_read_size(uint8_t * rspbuf,uint8_t * rsplen)106 ble_ll_whitelist_read_size(uint8_t *rspbuf, uint8_t *rsplen)
107 {
108 rspbuf[0] = BLE_LL_WHITELIST_SIZE;
109 *rsplen = 1;
110 return BLE_ERR_SUCCESS;
111 }
112
113 /**
114 * Searches the whitelist to determine if the address is present in the
115 * whitelist. This is an internal API that only searches the link layer
116 * whitelist and does not care about the hardware whitelist
117 *
118 * @param addr Device or identity address to check.
119 * @param addr_type Public address (0) or random address (1)
120 *
121 * @return int 0: device is not on whitelist; otherwise the return value
122 * is the 'position' of the device in the whitelist (the index of the element
123 * plus 1).
124 */
125 static int
ble_ll_whitelist_search(uint8_t * addr,uint8_t addr_type)126 ble_ll_whitelist_search(uint8_t *addr, uint8_t addr_type)
127 {
128 int i;
129 struct ble_ll_whitelist_entry *wl;
130
131 wl = &g_ble_ll_whitelist[0];
132 for (i = 0; i < BLE_LL_WHITELIST_SIZE; ++i) {
133 if ((wl->wl_valid) && (wl->wl_addr_type == addr_type) &&
134 (!memcmp(&wl->wl_dev_addr[0], addr, BLE_DEV_ADDR_LEN))) {
135 return i + 1;
136 }
137 ++wl;
138 }
139
140 return 0;
141 }
142
143 /**
144 * Is there a match between the device and a device on the whitelist.
145 *
146 * NOTE: This API uses the HW, if present, to determine if there was a match
147 * between a received address and an address in the whitelist. If the HW does
148 * not support whitelisting this API is the same as the whitelist search API
149 *
150 * @param addr
151 * @param addr_type Public address (0) or random address (1)
152 * @param is_ident True if addr is an identity address; false otherwise
153 *
154 * @return int
155 */
156 int
ble_ll_whitelist_match(uint8_t * addr,uint8_t addr_type,int is_ident)157 ble_ll_whitelist_match(uint8_t *addr, uint8_t addr_type, int is_ident)
158 {
159 int rc;
160 #if (BLE_USES_HW_WHITELIST == 1)
161 /*
162 * XXX: This should be changed. This is HW specific: some HW may be able
163 * to both resolve a private address and perform a whitelist check. The
164 * current BLE hw cannot support this.
165 */
166 if (is_ident) {
167 rc = ble_ll_whitelist_search(addr, addr_type);
168 } else {
169 rc = ble_hw_whitelist_match();
170 }
171 #else
172 rc = ble_ll_whitelist_search(addr, addr_type);
173 #endif
174 return rc;
175 }
176
177 /**
178 * Add a device to the whitelist
179 *
180 * @return int
181 */
182 int
ble_ll_whitelist_add(uint8_t * addr,uint8_t addr_type)183 ble_ll_whitelist_add(uint8_t *addr, uint8_t addr_type)
184 {
185 int i;
186 int rc;
187 struct ble_ll_whitelist_entry *wl;
188
189 /* Must be in proper state */
190 if (!ble_ll_whitelist_chg_allowed()) {
191 return BLE_ERR_CMD_DISALLOWED;
192 }
193
194 /* Check if we have any open entries */
195 rc = BLE_ERR_SUCCESS;
196 if (!ble_ll_whitelist_search(addr, addr_type)) {
197 wl = &g_ble_ll_whitelist[0];
198 for (i = 0; i < BLE_LL_WHITELIST_SIZE; ++i) {
199 if (wl->wl_valid == 0) {
200 memcpy(&wl->wl_dev_addr[0], addr, BLE_DEV_ADDR_LEN);
201 wl->wl_addr_type = addr_type;
202 wl->wl_valid = 1;
203 break;
204 }
205 ++wl;
206 }
207
208 if (i == BLE_LL_WHITELIST_SIZE) {
209 rc = BLE_ERR_MEM_CAPACITY;
210 } else {
211 #if (BLE_USES_HW_WHITELIST == 1)
212 rc = ble_hw_whitelist_add(addr, addr_type);
213 #endif
214 }
215 }
216
217 return rc;
218 }
219
220 /**
221 * Remove a device from the whitelist
222 *
223 * @param cmdbuf
224 *
225 * @return int 0: success, BLE error code otherwise
226 */
227 int
ble_ll_whitelist_rmv(uint8_t * addr,uint8_t addr_type)228 ble_ll_whitelist_rmv(uint8_t *addr, uint8_t addr_type)
229 {
230 int position;
231
232 /* Must be in proper state */
233 if (!ble_ll_whitelist_chg_allowed()) {
234 return BLE_ERR_CMD_DISALLOWED;
235 }
236
237 position = ble_ll_whitelist_search(addr, addr_type);
238 if (position) {
239 g_ble_ll_whitelist[position - 1].wl_valid = 0;
240 }
241
242 #if (BLE_USES_HW_WHITELIST == 1)
243 ble_hw_whitelist_rmv(addr, addr_type);
244 #endif
245
246 return BLE_ERR_SUCCESS;
247 }
248
249 /**
250 * Enable whitelisting.
251 *
252 * Note: This function has no effect if we are not using HW whitelisting
253 */
254 void
ble_ll_whitelist_enable(void)255 ble_ll_whitelist_enable(void)
256 {
257 #if (BLE_USES_HW_WHITELIST == 1)
258 ble_hw_whitelist_enable();
259 #endif
260 }
261
262 /**
263 * Disable whitelisting.
264 *
265 * Note: This function has no effect if we are not using HW whitelisting
266 */
267 void
ble_ll_whitelist_disable(void)268 ble_ll_whitelist_disable(void)
269 {
270 #if (BLE_USES_HW_WHITELIST == 1)
271 ble_hw_whitelist_disable();
272 #endif
273 }
274