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