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