1 // Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include <ctype.h>
16 #include <stdio.h>
17 #include <string.h>
18 
19 #include "common/bt_defs.h"
20 #include "common/bt_trace.h"
21 #include "osi/alarm.h"
22 #include "osi/allocator.h"
23 #include "device/bdaddr.h"
24 #include "btc/btc_config.h"
25 #include "btc/btc_util.h"
26 #include "osi/config.h"
27 #include "osi/osi.h"
28 #include "osi/mutex.h"
29 
30 #include "stack/bt_types.h"
31 
32 static const char *CONFIG_FILE_PATH = "bt_config.conf";
33 static const period_ms_t CONFIG_SETTLE_PERIOD_MS = 3000;
34 
35 static void btc_key_value_to_string(uint8_t *key_value, char *value_str, int key_length);
36 static osi_mutex_t lock;  // protects operations on |config|.
37 static config_t *config;
38 
btc_compare_address_key_value(const char * section,const char * key_type,void * key_value,int key_length)39 bool btc_compare_address_key_value(const char *section, const char *key_type, void *key_value, int key_length)
40 {
41     assert(key_value != NULL);
42     bool status = false;
43     char value_str[100] = {0};
44     if(key_length > sizeof(value_str)/2) {
45         return false;
46     }
47     btc_key_value_to_string((uint8_t *)key_value, value_str, key_length);
48     if ((status = config_has_key_in_section(config, key_type, value_str)) == true) {
49         config_remove_section(config, section);
50     }
51     return status;
52 }
53 
btc_key_value_to_string(uint8_t * key_value,char * value_str,int key_length)54 static void btc_key_value_to_string(uint8_t *key_value, char *value_str, int key_length)
55 {
56     const char *lookup = "0123456789abcdef";
57 
58     assert(key_value != NULL);
59     assert(value_str != NULL);
60 
61     for (size_t i = 0; i < key_length; ++i) {
62         value_str[(i * 2) + 0] = lookup[(key_value[i] >> 4) & 0x0F];
63         value_str[(i * 2) + 1] = lookup[key_value[i] & 0x0F];
64     }
65 
66     return;
67 }
68 
69 // Module lifecycle functions
70 
btc_config_init(void)71 bool btc_config_init(void)
72 {
73     osi_mutex_new(&lock);
74     config = config_new(CONFIG_FILE_PATH);
75     if (!config) {
76         BTC_TRACE_WARNING("%s unable to load config file; starting unconfigured.\n", __func__);
77         config = config_new_empty();
78         if (!config) {
79             BTC_TRACE_ERROR("%s unable to allocate a config object.\n", __func__);
80             goto error;
81         }
82     }
83     if (config_save(config, CONFIG_FILE_PATH)) {
84         // unlink(LEGACY_CONFIG_FILE_PATH);
85     }
86 
87     return true;
88 
89 error:;
90     config_free(config);
91     osi_mutex_free(&lock);
92     config = NULL;
93     BTC_TRACE_ERROR("%s failed\n", __func__);
94     return false;
95 }
96 
btc_config_shut_down(void)97 bool btc_config_shut_down(void)
98 {
99     btc_config_flush();
100     return true;
101 }
102 
btc_config_clean_up(void)103 bool btc_config_clean_up(void)
104 {
105     btc_config_flush();
106 
107     config_free(config);
108     osi_mutex_free(&lock);
109     config = NULL;
110     return true;
111 }
112 
btc_config_has_section(const char * section)113 bool btc_config_has_section(const char *section)
114 {
115     assert(config != NULL);
116     assert(section != NULL);
117 
118     return config_has_section(config, section);
119 }
120 
btc_config_exist(const char * section,const char * key)121 bool btc_config_exist(const char *section, const char *key)
122 {
123     assert(config != NULL);
124     assert(section != NULL);
125     assert(key != NULL);
126 
127     return config_has_key(config, section, key);
128 }
129 
btc_config_get_int(const char * section,const char * key,int * value)130 bool btc_config_get_int(const char *section, const char *key, int *value)
131 {
132     assert(config != NULL);
133     assert(section != NULL);
134     assert(key != NULL);
135     assert(value != NULL);
136 
137     bool ret = config_has_key(config, section, key);
138     if (ret) {
139         *value = config_get_int(config, section, key, *value);
140     }
141 
142     return ret;
143 }
144 
btc_config_set_int(const char * section,const char * key,int value)145 bool btc_config_set_int(const char *section, const char *key, int value)
146 {
147     assert(config != NULL);
148     assert(section != NULL);
149     assert(key != NULL);
150 
151     config_set_int(config, section, key, value);
152 
153     return true;
154 }
155 
btc_config_get_str(const char * section,const char * key,char * value,int * size_bytes)156 bool btc_config_get_str(const char *section, const char *key, char *value, int *size_bytes)
157 {
158     assert(config != NULL);
159     assert(section != NULL);
160     assert(key != NULL);
161     assert(value != NULL);
162     assert(size_bytes != NULL);
163 
164     const char *stored_value = config_get_string(config, section, key, NULL);
165 
166     if (!stored_value) {
167         return false;
168     }
169 
170     strlcpy(value, stored_value, *size_bytes);
171     *size_bytes = strlen(value) + 1;
172 
173     return true;
174 }
175 
btc_config_set_str(const char * section,const char * key,const char * value)176 bool btc_config_set_str(const char *section, const char *key, const char *value)
177 {
178     assert(config != NULL);
179     assert(section != NULL);
180     assert(key != NULL);
181     assert(value != NULL);
182 
183     config_set_string(config, section, key, value, false);
184 
185     return true;
186 }
187 
btc_config_get_bin(const char * section,const char * key,uint8_t * value,size_t * length)188 bool btc_config_get_bin(const char *section, const char *key, uint8_t *value, size_t *length)
189 {
190     assert(config != NULL);
191     assert(section != NULL);
192     assert(key != NULL);
193     assert(value != NULL);
194     assert(length != NULL);
195 
196     const char *value_str = config_get_string(config, section, key, NULL);
197 
198     if (!value_str) {
199         return false;
200     }
201 
202     size_t value_len = strlen(value_str);
203     if ((value_len % 2) != 0 || *length < (value_len / 2)) {
204         return false;
205     }
206 
207     for (size_t i = 0; i < value_len; ++i)
208         if (!isxdigit((unsigned char)value_str[i])) {
209             return false;
210         }
211 
212     for (*length = 0; *value_str; value_str += 2, *length += 1) {
213         unsigned int val;
214         sscanf(value_str, "%02x", &val);
215         value[*length] = (uint8_t)(val);
216     }
217 
218     return true;
219 }
220 
btc_config_get_bin_length(const char * section,const char * key)221 size_t btc_config_get_bin_length(const char *section, const char *key)
222 {
223     assert(config != NULL);
224     assert(section != NULL);
225     assert(key != NULL);
226 
227     const char *value_str = config_get_string(config, section, key, NULL);
228 
229     if (!value_str) {
230         return 0;
231     }
232 
233     size_t value_len = strlen(value_str);
234     return ((value_len % 2) != 0) ? 0 : (value_len / 2);
235 }
236 
btc_config_set_bin(const char * section,const char * key,const uint8_t * value,size_t length)237 bool btc_config_set_bin(const char *section, const char *key, const uint8_t *value, size_t length)
238 {
239     const char *lookup = "0123456789abcdef";
240 
241     assert(config != NULL);
242     assert(section != NULL);
243     assert(key != NULL);
244 
245     if (length > 0) {
246         assert(value != NULL);
247     }
248 
249     char *str = (char *)osi_calloc(length * 2 + 1);
250     if (!str) {
251         return false;
252     }
253 
254     for (size_t i = 0; i < length; ++i) {
255         str[(i * 2) + 0] = lookup[(value[i] >> 4) & 0x0F];
256         str[(i * 2) + 1] = lookup[value[i] & 0x0F];
257     }
258 
259     config_set_string(config, section, key, str, false);
260 
261     osi_free(str);
262     return true;
263 }
264 
btc_config_section_begin(void)265 const btc_config_section_iter_t *btc_config_section_begin(void)
266 {
267     assert(config != NULL);
268     return (const btc_config_section_iter_t *)config_section_begin(config);
269 }
270 
btc_config_section_end(void)271 const btc_config_section_iter_t *btc_config_section_end(void)
272 {
273     assert(config != NULL);
274     return (const btc_config_section_iter_t *)config_section_end(config);
275 }
276 
btc_config_section_next(const btc_config_section_iter_t * section)277 const btc_config_section_iter_t *btc_config_section_next(const btc_config_section_iter_t *section)
278 {
279     assert(config != NULL);
280     assert(section != NULL);
281     return (const btc_config_section_iter_t *)config_section_next((const config_section_node_t *)section);
282 }
283 
btc_config_section_name(const btc_config_section_iter_t * section)284 const char *btc_config_section_name(const btc_config_section_iter_t *section)
285 {
286     assert(config != NULL);
287     assert(section != NULL);
288     return config_section_name((const config_section_node_t *)section);
289 }
290 
291 
292 
btc_config_remove(const char * section,const char * key)293 bool btc_config_remove(const char *section, const char *key)
294 {
295     assert(config != NULL);
296     assert(section != NULL);
297     assert(key != NULL);
298 
299     return config_remove_key(config, section, key);
300 }
301 
btc_config_remove_section(const char * section)302 bool btc_config_remove_section(const char *section)
303 {
304     assert(config != NULL);
305     assert(section != NULL);
306 
307     return config_remove_section(config, section);
308 }
309 
btc_config_flush(void)310 void btc_config_flush(void)
311 {
312     assert(config != NULL);
313 
314     config_save(config, CONFIG_FILE_PATH);
315 }
316 
btc_config_clear(void)317 int btc_config_clear(void)
318 {
319     assert(config != NULL);
320 
321     config_free(config);
322 
323     config = config_new_empty();
324     if (config == NULL) {
325         return false;
326     }
327     int ret = config_save(config, CONFIG_FILE_PATH);
328     return ret;
329 }
330 
btc_config_lock(void)331 void btc_config_lock(void)
332 {
333     osi_mutex_lock(&lock, OSI_MUTEX_MAX_TIMEOUT);
334 }
335 
btc_config_unlock(void)336 void btc_config_unlock(void)
337 {
338     osi_mutex_unlock(&lock);
339 }
340