xref: /nrf52832-nimble/packages/NimBLE-latest/nimble/controller/src/ble_ll_whitelist.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 <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