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 "os/log.h"
36 #include "osi/include/alarm.h"
37 #include "osi/include/allocator.h"
38 #include "osi/include/compat.h"
39 #include "osi/include/config.h"
40 
41 enum ConfigSource device_iot_config_source = NOT_LOADED;
42 
43 int device_iot_config_devices_loaded = -1;
44 char device_iot_config_time_created[TIME_STRING_LENGTH];
45 
46 std::mutex config_lock;  // protects operations on |config|.
47 std::unique_ptr<config_t> config;
48 alarm_t* config_timer;
49 
50 using namespace bluetooth;
51 
device_iot_config_has_section(const std::string & section)52 bool device_iot_config_has_section(const std::string& section) {
53   if (!com::android::bluetooth::flags::device_iot_config_logging())
54     return false;
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,
63                              const std::string& key) {
64   if (!com::android::bluetooth::flags::device_iot_config_logging())
65     return false;
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,
74                                const std::string& key, int& value) {
75   if (!com::android::bluetooth::flags::device_iot_config_logging())
76     return false;
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) value = config_get_int(*config, section, key, value);
83 
84   return ret;
85 }
86 
device_iot_config_set_int(const std::string & section,const std::string & key,int value)87 bool device_iot_config_set_int(const std::string& section,
88                                const std::string& key, int value) {
89   if (!com::android::bluetooth::flags::device_iot_config_logging())
90     return false;
91 
92   log::assert_that(config != NULL, "assert failed: config != NULL");
93 
94   std::unique_lock<std::mutex> lock(config_lock);
95   char value_str[32] = {0};
96   snprintf(value_str, sizeof(value_str), "%d", value);
97   if (device_iot_config_has_key_value(section, key, value_str)) return true;
98 
99   config_set_string(config.get(), section, key, value_str);
100   device_iot_config_save_async();
101 
102   return true;
103 }
104 
device_iot_config_int_add_one(const std::string & section,const std::string & key)105 bool device_iot_config_int_add_one(const std::string& section,
106                                    const std::string& key) {
107   if (!com::android::bluetooth::flags::device_iot_config_logging())
108     return false;
109 
110   log::assert_that(config != NULL, "assert failed: config != NULL");
111 
112   int result = 0;
113   std::unique_lock<std::mutex> lock(config_lock);
114   result = config_get_int(*config, section, key, result);
115   if (result >= 0) {
116     result += 1;
117   } else {
118     result = 0;
119   }
120   config_set_int(config.get(), section, key, result);
121   device_iot_config_save_async();
122 
123   return true;
124 }
125 
device_iot_config_get_hex(const std::string & section,const std::string & key,int & value)126 bool device_iot_config_get_hex(const std::string& section,
127                                const std::string& key, int& value) {
128   if (!com::android::bluetooth::flags::device_iot_config_logging())
129     return false;
130 
131   log::assert_that(config != NULL, "assert failed: config != NULL");
132 
133   std::unique_lock<std::mutex> lock(config_lock);
134   const std::string* stored_value =
135       config_get_string(*config, section, key, NULL);
136   if (!stored_value) return false;
137 
138   errno = 0;
139   char* endptr = nullptr;
140   int result = strtoul(stored_value->c_str(), &endptr, 16);
141   if (stored_value->c_str() == endptr) return false;
142   if (endptr == nullptr || endptr[0] != '\0') return false;
143   if (errno) return false;
144 
145   value = result;
146   return true;
147 }
148 
device_iot_config_set_hex(const std::string & section,const std::string & key,int value,int byte_num)149 bool device_iot_config_set_hex(const std::string& section,
150                                const std::string& key, int value,
151                                int byte_num) {
152   if (!com::android::bluetooth::flags::device_iot_config_logging())
153     return false;
154 
155   log::assert_that(config != NULL, "assert failed: config != NULL");
156 
157   char value_str[32] = {0};
158   if (byte_num == 1)
159     snprintf(value_str, sizeof(value_str), "%02x", value);
160   else if (byte_num == 2)
161     snprintf(value_str, sizeof(value_str), "%04x", value);
162   else if (byte_num == 3)
163     snprintf(value_str, sizeof(value_str), "%06x", value);
164   else if (byte_num == 4)
165     snprintf(value_str, sizeof(value_str), "%08x", value);
166 
167   std::unique_lock<std::mutex> lock(config_lock);
168   if (device_iot_config_has_key_value(section, key, value_str)) return true;
169 
170   config_set_string(config.get(), section, key, value_str);
171   device_iot_config_save_async();
172 
173   return true;
174 }
175 
device_iot_config_set_hex_if_greater(const std::string & section,const std::string & key,int value,int byte_num)176 bool device_iot_config_set_hex_if_greater(const std::string& section,
177                                           const std::string& key, int value,
178                                           int byte_num) {
179   if (!com::android::bluetooth::flags::device_iot_config_logging())
180     return false;
181 
182   int stored_value = 0;
183   bool ret = device_iot_config_get_hex(section, key, stored_value);
184   if (ret && stored_value >= value) return true;
185 
186   return device_iot_config_set_hex(section, key, value, byte_num);
187 }
188 
device_iot_config_get_str(const std::string & section,const std::string & key,char * value,int * size_bytes)189 bool device_iot_config_get_str(const std::string& section,
190                                const std::string& key, char* value,
191                                int* size_bytes) {
192   if (!com::android::bluetooth::flags::device_iot_config_logging())
193     return false;
194 
195   log::assert_that(config != NULL, "assert failed: config != NULL");
196   log::assert_that(value != NULL, "assert failed: value != NULL");
197   log::assert_that(size_bytes != NULL, "assert failed: size_bytes != NULL");
198 
199   std::unique_lock<std::mutex> lock(config_lock);
200   const std::string* stored_value =
201       config_get_string(*config, section, key, NULL);
202 
203   if (!stored_value) return false;
204 
205   strlcpy(value, stored_value->c_str(), *size_bytes);
206   *size_bytes = strlen(value) + 1;
207 
208   return true;
209 }
210 
device_iot_config_set_str(const std::string & section,const std::string & key,const std::string & value)211 bool device_iot_config_set_str(const std::string& section,
212                                const std::string& key,
213                                const std::string& value) {
214   if (!com::android::bluetooth::flags::device_iot_config_logging())
215     return false;
216 
217   log::assert_that(config != NULL, "assert failed: config != NULL");
218 
219   std::unique_lock<std::mutex> lock(config_lock);
220   if (device_iot_config_has_key_value(section, key, value)) return true;
221 
222   config_set_string(config.get(), section, key, value);
223   device_iot_config_save_async();
224 
225   return true;
226 }
227 
device_iot_config_get_bin(const std::string & section,const std::string & key,uint8_t * value,size_t * length)228 bool device_iot_config_get_bin(const std::string& section,
229                                const std::string& key, uint8_t* value,
230                                size_t* length) {
231   if (!com::android::bluetooth::flags::device_iot_config_logging())
232     return false;
233 
234   log::assert_that(config != NULL, "assert failed: config != NULL");
235   log::assert_that(value != NULL, "assert failed: value != NULL");
236   log::assert_that(length != NULL, "assert failed: length != NULL");
237 
238   std::unique_lock<std::mutex> lock(config_lock);
239   const std::string* value_string =
240       config_get_string(*config, section, key, NULL);
241 
242   if (!value_string) return false;
243 
244   const char* value_str = value_string->c_str();
245 
246   size_t value_len = strlen(value_str);
247   if ((value_len % 2) != 0 || *length < (value_len / 2)) return false;
248 
249   for (size_t i = 0; i < value_len; ++i)
250     if (!isxdigit(value_str[i])) return false;
251 
252   for (*length = 0; *value_str; value_str += 2, *length += 1) {
253     errno = 0;
254     char* endptr = nullptr;
255     value[*length] = strtoul(value_str, &endptr, 16);
256     if (value_str == endptr) return false;
257     if (*endptr) return false;
258     if (errno) return false;
259   }
260 
261   return true;
262 }
263 
device_iot_config_get_bin_length(const std::string & section,const std::string & key)264 size_t device_iot_config_get_bin_length(const std::string& section,
265                                         const std::string& key) {
266   if (!com::android::bluetooth::flags::device_iot_config_logging()) return 0;
267 
268   log::assert_that(config != NULL, "assert failed: config != NULL");
269 
270   std::unique_lock<std::mutex> lock(config_lock);
271   const std::string* value_str = config_get_string(*config, section, key, NULL);
272 
273   if (!value_str) return 0;
274 
275   size_t value_len = strlen(value_str->c_str());
276   return ((value_len % 2) != 0) ? 0 : (value_len / 2);
277 }
278 
device_iot_config_set_bin(const std::string & section,const std::string & key,const uint8_t * value,size_t length)279 bool device_iot_config_set_bin(const std::string& section,
280                                const std::string& key, const uint8_t* value,
281                                size_t length) {
282   if (!com::android::bluetooth::flags::device_iot_config_logging())
283     return false;
284 
285   const char* lookup = "0123456789abcdef";
286 
287   log::assert_that(config != NULL, "assert failed: config != NULL");
288 
289   log::verbose("Key = {}", key);
290   if (length > 0)
291     log::assert_that(value != NULL, "assert failed: value != NULL");
292 
293   char* str = (char*)osi_calloc(length * 2 + 1);
294   if (str == NULL) {
295     log::error("Unable to allocate a str.");
296     return false;
297   }
298 
299   for (size_t i = 0; i < length; ++i) {
300     str[(i * 2) + 0] = lookup[(value[i] >> 4) & 0x0F];
301     str[(i * 2) + 1] = lookup[value[i] & 0x0F];
302   }
303 
304   std::unique_lock<std::mutex> lock(config_lock);
305   if (device_iot_config_has_key_value(section, key, str)) {
306     osi_free(str);
307     return true;
308   }
309 
310   config_set_string(config.get(), section, key, str);
311   device_iot_config_save_async();
312 
313   osi_free(str);
314   return true;
315 }
316 
device_iot_config_remove(const std::string & section,const std::string & key)317 bool device_iot_config_remove(const std::string& section,
318                               const std::string& key) {
319   if (!com::android::bluetooth::flags::device_iot_config_logging())
320     return false;
321 
322   log::assert_that(config != NULL, "assert failed: config != NULL");
323 
324   std::unique_lock<std::mutex> lock(config_lock);
325   return config_remove_key(config.get(), section, key);
326 }
327 
device_iot_config_flush(void)328 void device_iot_config_flush(void) {
329   if (!com::android::bluetooth::flags::device_iot_config_logging()) return;
330 
331   log::assert_that(config != NULL, "assert failed: config != NULL");
332   log::assert_that(config_timer != NULL, "assert failed: config_timer != NULL");
333 
334   int event = alarm_is_scheduled(config_timer) ? IOT_CONFIG_SAVE_TIMER_FIRED_EVT
335                                                : IOT_CONFIG_FLUSH_EVT;
336   log::verbose("evt={}", event);
337   alarm_cancel(config_timer);
338   device_iot_config_write(event, NULL);
339 }
340 
device_iot_config_clear(void)341 bool device_iot_config_clear(void) {
342   if (!com::android::bluetooth::flags::device_iot_config_logging()) return true;
343 
344   log::assert_that(config != NULL, "assert failed: config != NULL");
345   log::assert_that(config_timer != NULL, "assert failed: config_timer != NULL");
346 
347   log::info("");
348   alarm_cancel(config_timer);
349 
350   std::unique_lock<std::mutex> lock(config_lock);
351   config.reset();
352 
353   config = config_new_empty();
354   if (config == NULL) {
355     return false;
356   }
357 
358   bool ret = config_save(*config, IOT_CONFIG_FILE_PATH);
359   device_iot_config_source = RESET;
360   return ret;
361 }
362 
device_debug_iot_config_dump(int fd)363 void device_debug_iot_config_dump(int fd) {
364   if (!com::android::bluetooth::flags::device_iot_config_logging()) return;
365 
366   dprintf(fd, "\nBluetooth Iot Config:\n");
367 
368   dprintf(fd, "  Config Source: ");
369   switch (device_iot_config_source) {
370     case NOT_LOADED:
371       dprintf(fd, "Not loaded\n");
372       break;
373     case ORIGINAL:
374       dprintf(fd, "Original file\n");
375       break;
376     case BACKUP:
377       dprintf(fd, "Backup file\n");
378       break;
379     case NEW_FILE:
380       dprintf(fd, "New file\n");
381       break;
382     case RESET:
383       dprintf(fd, "Reset file\n");
384       break;
385   }
386 
387   dprintf(fd, "  Devices loaded: %d\n", device_iot_config_devices_loaded);
388   dprintf(fd, "  File created/tagged: %s\n", device_iot_config_time_created);
389 }
390