1 /******************************************************************************
2 *
3 * Copyright (C) 2014 Google, Inc.
4 * Copyright (C) 2018 The Linux Foundation
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * 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, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 *
18 ******************************************************************************/
19 #define LOG_TAG "device_iot_config"
20
21 #include "device/include/device_iot_config.h"
22
23 #include <bluetooth/log.h>
24 #include <com_android_bluetooth_flags.h>
25 #include <ctype.h>
26 #include <string.h>
27 #include <time.h>
28 #include <unistd.h>
29
30 #include <mutex>
31 #include <string>
32
33 #include "device_iot_config_int.h"
34 #include "internal_include/bt_target.h"
35 #include "osi/include/alarm.h"
36 #include "osi/include/allocator.h"
37 #include "osi/include/compat.h"
38 #include "osi/include/config.h"
39
40 enum ConfigSource device_iot_config_source = NOT_LOADED;
41
42 int device_iot_config_devices_loaded = -1;
43 char device_iot_config_time_created[TIME_STRING_LENGTH];
44
45 std::mutex config_lock; // protects operations on |config|.
46 std::unique_ptr<config_t> config;
47 alarm_t* config_timer;
48
49 using namespace bluetooth;
50
device_iot_config_has_section(const std::string & section)51 bool device_iot_config_has_section(const std::string& section) {
52 if (!com::android::bluetooth::flags::device_iot_config_logging()) {
53 return false;
54 }
55
56 log::assert_that(config != NULL, "assert failed: config != NULL");
57
58 std::unique_lock<std::mutex> lock(config_lock);
59 return config_has_section(*config, section);
60 }
61
device_iot_config_exist(const std::string & section,const std::string & key)62 bool device_iot_config_exist(const std::string& section, const std::string& key) {
63 if (!com::android::bluetooth::flags::device_iot_config_logging()) {
64 return false;
65 }
66
67 log::assert_that(config != NULL, "assert failed: config != NULL");
68
69 std::unique_lock<std::mutex> lock(config_lock);
70 return config_has_key(*config, section, key);
71 }
72
device_iot_config_get_int(const std::string & section,const std::string & key,int & value)73 bool device_iot_config_get_int(const std::string& section, const std::string& key, int& value) {
74 if (!com::android::bluetooth::flags::device_iot_config_logging()) {
75 return false;
76 }
77
78 log::assert_that(config != NULL, "assert failed: config != NULL");
79
80 std::unique_lock<std::mutex> lock(config_lock);
81 bool ret = config_has_key(*config, section, key);
82 if (ret) {
83 value = config_get_int(*config, section, key, value);
84 }
85
86 return ret;
87 }
88
device_iot_config_set_int(const std::string & section,const std::string & key,int value)89 bool device_iot_config_set_int(const std::string& section, const std::string& key, int value) {
90 if (!com::android::bluetooth::flags::device_iot_config_logging()) {
91 return false;
92 }
93
94 log::assert_that(config != NULL, "assert failed: config != NULL");
95
96 std::unique_lock<std::mutex> lock(config_lock);
97 char value_str[32] = {0};
98 snprintf(value_str, sizeof(value_str), "%d", value);
99 if (device_iot_config_has_key_value(section, key, value_str)) {
100 return true;
101 }
102
103 config_set_string(config.get(), section, key, value_str);
104 device_iot_config_save_async();
105
106 return true;
107 }
108
device_iot_config_int_add_one(const std::string & section,const std::string & key)109 bool device_iot_config_int_add_one(const std::string& section, const std::string& key) {
110 if (!com::android::bluetooth::flags::device_iot_config_logging()) {
111 return false;
112 }
113
114 log::assert_that(config != NULL, "assert failed: config != NULL");
115
116 int result = 0;
117 std::unique_lock<std::mutex> lock(config_lock);
118 result = config_get_int(*config, section, key, result);
119 if (result >= 0) {
120 result += 1;
121 } else {
122 result = 0;
123 }
124 config_set_int(config.get(), section, key, result);
125 device_iot_config_save_async();
126
127 return true;
128 }
129
device_iot_config_get_hex(const std::string & section,const std::string & key,int & value)130 bool device_iot_config_get_hex(const std::string& section, const std::string& key, int& value) {
131 if (!com::android::bluetooth::flags::device_iot_config_logging()) {
132 return false;
133 }
134
135 log::assert_that(config != NULL, "assert failed: config != NULL");
136
137 std::unique_lock<std::mutex> lock(config_lock);
138 const std::string* stored_value = config_get_string(*config, section, key, NULL);
139 if (!stored_value) {
140 return false;
141 }
142
143 errno = 0;
144 char* endptr = nullptr;
145 int result = strtoul(stored_value->c_str(), &endptr, 16);
146 if (stored_value->c_str() == endptr) {
147 return false;
148 }
149 if (endptr == nullptr || endptr[0] != '\0') {
150 return false;
151 }
152 if (errno) {
153 return false;
154 }
155
156 value = result;
157 return true;
158 }
159
device_iot_config_set_hex(const std::string & section,const std::string & key,int value,int byte_num)160 bool device_iot_config_set_hex(const std::string& section, const std::string& key, int value,
161 int byte_num) {
162 if (!com::android::bluetooth::flags::device_iot_config_logging()) {
163 return false;
164 }
165
166 log::assert_that(config != NULL, "assert failed: config != NULL");
167
168 char value_str[32] = {0};
169 if (byte_num == 1) {
170 snprintf(value_str, sizeof(value_str), "%02x", value);
171 } else if (byte_num == 2) {
172 snprintf(value_str, sizeof(value_str), "%04x", value);
173 } else if (byte_num == 3) {
174 snprintf(value_str, sizeof(value_str), "%06x", value);
175 } else if (byte_num == 4) {
176 snprintf(value_str, sizeof(value_str), "%08x", value);
177 }
178
179 std::unique_lock<std::mutex> lock(config_lock);
180 if (device_iot_config_has_key_value(section, key, value_str)) {
181 return true;
182 }
183
184 config_set_string(config.get(), section, key, value_str);
185 device_iot_config_save_async();
186
187 return true;
188 }
189
device_iot_config_set_hex_if_greater(const std::string & section,const std::string & key,int value,int byte_num)190 bool device_iot_config_set_hex_if_greater(const std::string& section, const std::string& key,
191 int value, int byte_num) {
192 if (!com::android::bluetooth::flags::device_iot_config_logging()) {
193 return false;
194 }
195
196 int stored_value = 0;
197 bool ret = device_iot_config_get_hex(section, key, stored_value);
198 if (ret && stored_value >= value) {
199 return true;
200 }
201
202 return device_iot_config_set_hex(section, key, value, byte_num);
203 }
204
device_iot_config_get_str(const std::string & section,const std::string & key,char * value,int * size_bytes)205 bool device_iot_config_get_str(const std::string& section, const std::string& key, char* value,
206 int* size_bytes) {
207 if (!com::android::bluetooth::flags::device_iot_config_logging()) {
208 return false;
209 }
210
211 log::assert_that(config != NULL, "assert failed: config != NULL");
212 log::assert_that(value != NULL, "assert failed: value != NULL");
213 log::assert_that(size_bytes != NULL, "assert failed: size_bytes != NULL");
214
215 std::unique_lock<std::mutex> lock(config_lock);
216 const std::string* stored_value = config_get_string(*config, section, key, NULL);
217
218 if (!stored_value) {
219 return false;
220 }
221
222 osi_strlcpy(value, stored_value->c_str(), *size_bytes);
223 *size_bytes = strlen(value) + 1;
224
225 return true;
226 }
227
device_iot_config_set_str(const std::string & section,const std::string & key,const std::string & value)228 bool device_iot_config_set_str(const std::string& section, const std::string& key,
229 const std::string& value) {
230 if (!com::android::bluetooth::flags::device_iot_config_logging()) {
231 return false;
232 }
233
234 log::assert_that(config != NULL, "assert failed: config != NULL");
235
236 std::unique_lock<std::mutex> lock(config_lock);
237 if (device_iot_config_has_key_value(section, key, value)) {
238 return true;
239 }
240
241 config_set_string(config.get(), section, key, value);
242 device_iot_config_save_async();
243
244 return true;
245 }
246
device_iot_config_get_bin(const std::string & section,const std::string & key,uint8_t * value,size_t * length)247 bool device_iot_config_get_bin(const std::string& section, const std::string& key, uint8_t* value,
248 size_t* length) {
249 if (!com::android::bluetooth::flags::device_iot_config_logging()) {
250 return false;
251 }
252
253 log::assert_that(config != NULL, "assert failed: config != NULL");
254 log::assert_that(value != NULL, "assert failed: value != NULL");
255 log::assert_that(length != NULL, "assert failed: length != NULL");
256
257 std::unique_lock<std::mutex> lock(config_lock);
258 const std::string* value_string = config_get_string(*config, section, key, NULL);
259
260 if (!value_string) {
261 return false;
262 }
263
264 const char* value_str = value_string->c_str();
265
266 size_t value_len = strlen(value_str);
267 if ((value_len % 2) != 0 || *length < (value_len / 2)) {
268 return false;
269 }
270
271 for (size_t i = 0; i < value_len; ++i) {
272 if (!isxdigit(value_str[i])) {
273 return false;
274 }
275 }
276
277 for (*length = 0; *value_str; value_str += 2, *length += 1) {
278 errno = 0;
279 char* endptr = nullptr;
280 value[*length] = strtoul(value_str, &endptr, 16);
281 if (value_str == endptr) {
282 return false;
283 }
284 if (*endptr) {
285 return false;
286 }
287 if (errno) {
288 return false;
289 }
290 }
291
292 return true;
293 }
294
device_iot_config_get_bin_length(const std::string & section,const std::string & key)295 size_t device_iot_config_get_bin_length(const std::string& section, const std::string& key) {
296 if (!com::android::bluetooth::flags::device_iot_config_logging()) {
297 return 0;
298 }
299
300 log::assert_that(config != NULL, "assert failed: config != NULL");
301
302 std::unique_lock<std::mutex> lock(config_lock);
303 const std::string* value_str = config_get_string(*config, section, key, NULL);
304
305 if (!value_str) {
306 return 0;
307 }
308
309 size_t value_len = strlen(value_str->c_str());
310 return ((value_len % 2) != 0) ? 0 : (value_len / 2);
311 }
312
device_iot_config_set_bin(const std::string & section,const std::string & key,const uint8_t * value,size_t length)313 bool device_iot_config_set_bin(const std::string& section, const std::string& key,
314 const uint8_t* value, size_t length) {
315 if (!com::android::bluetooth::flags::device_iot_config_logging()) {
316 return false;
317 }
318
319 const char* lookup = "0123456789abcdef";
320
321 log::assert_that(config != NULL, "assert failed: config != NULL");
322
323 log::verbose("Key = {}", key);
324 if (length > 0) {
325 log::assert_that(value != NULL, "assert failed: value != NULL");
326 }
327
328 char* str = (char*)osi_calloc(length * 2 + 1);
329 if (str == NULL) {
330 log::error("Unable to allocate a str.");
331 return false;
332 }
333
334 for (size_t i = 0; i < length; ++i) {
335 str[(i * 2) + 0] = lookup[(value[i] >> 4) & 0x0F];
336 str[(i * 2) + 1] = lookup[value[i] & 0x0F];
337 }
338
339 std::unique_lock<std::mutex> lock(config_lock);
340 if (device_iot_config_has_key_value(section, key, str)) {
341 osi_free(str);
342 return true;
343 }
344
345 config_set_string(config.get(), section, key, str);
346 device_iot_config_save_async();
347
348 osi_free(str);
349 return true;
350 }
351
device_iot_config_remove(const std::string & section,const std::string & key)352 bool device_iot_config_remove(const std::string& section, const std::string& key) {
353 if (!com::android::bluetooth::flags::device_iot_config_logging()) {
354 return false;
355 }
356
357 log::assert_that(config != NULL, "assert failed: config != NULL");
358
359 std::unique_lock<std::mutex> lock(config_lock);
360 return config_remove_key(config.get(), section, key);
361 }
362
device_iot_config_flush(void)363 void device_iot_config_flush(void) {
364 if (!com::android::bluetooth::flags::device_iot_config_logging()) {
365 return;
366 }
367
368 log::assert_that(config != NULL, "assert failed: config != NULL");
369 log::assert_that(config_timer != NULL, "assert failed: config_timer != NULL");
370
371 int event =
372 alarm_is_scheduled(config_timer) ? IOT_CONFIG_SAVE_TIMER_FIRED_EVT : IOT_CONFIG_FLUSH_EVT;
373 log::verbose("evt={}", event);
374 alarm_cancel(config_timer);
375 device_iot_config_write(event, NULL);
376 }
377
device_iot_config_clear(void)378 bool device_iot_config_clear(void) {
379 if (!com::android::bluetooth::flags::device_iot_config_logging()) {
380 return true;
381 }
382
383 log::assert_that(config != NULL, "assert failed: config != NULL");
384 log::assert_that(config_timer != NULL, "assert failed: config_timer != NULL");
385
386 log::info("");
387 alarm_cancel(config_timer);
388
389 std::unique_lock<std::mutex> lock(config_lock);
390 config.reset();
391
392 config = config_new_empty();
393 if (config == NULL) {
394 return false;
395 }
396
397 bool ret = config_save(*config, IOT_CONFIG_FILE_PATH);
398 device_iot_config_source = RESET;
399 return ret;
400 }
401
device_debug_iot_config_dump(int fd)402 void device_debug_iot_config_dump(int fd) {
403 if (!com::android::bluetooth::flags::device_iot_config_logging()) {
404 return;
405 }
406
407 dprintf(fd, "\nBluetooth Iot Config:\n");
408
409 dprintf(fd, " Config Source: ");
410 switch (device_iot_config_source) {
411 case NOT_LOADED:
412 dprintf(fd, "Not loaded\n");
413 break;
414 case ORIGINAL:
415 dprintf(fd, "Original file\n");
416 break;
417 case BACKUP:
418 dprintf(fd, "Backup file\n");
419 break;
420 case NEW_FILE:
421 dprintf(fd, "New file\n");
422 break;
423 case RESET:
424 dprintf(fd, "Reset file\n");
425 break;
426 }
427
428 dprintf(fd, " Devices loaded: %d\n", device_iot_config_devices_loaded);
429 dprintf(fd, " File created/tagged: %s\n", device_iot_config_time_created);
430 }
431