• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "bt_target.h"
20 
21 #define LOG_TAG "device_iot_config"
22 #include <base/logging.h>
23 #include <ctype.h>
24 #include <stdio.h>
25 #include <string.h>
26 #include <time.h>
27 #include <unistd.h>
28 
29 #include <mutex>
30 #include <string>
31 
32 #include "bt_types.h"
33 #include "btcore/include/module.h"
34 #include "btif/include/btif_api.h"
35 #include "btif/include/btif_util.h"
36 #include "common/init_flags.h"
37 #include "device/include/device_iot_config.h"
38 #include "device_iot_config_int.h"
39 #include "osi/include/alarm.h"
40 #include "osi/include/allocator.h"
41 #include "osi/include/compat.h"
42 #include "osi/include/config.h"
43 #include "osi/include/log.h"
44 #include "osi/include/osi.h"
45 #include "osi/include/properties.h"
46 
47 enum ConfigSource device_iot_config_source = NOT_LOADED;
48 
49 int device_iot_config_devices_loaded = -1;
50 char device_iot_config_time_created[TIME_STRING_LENGTH];
51 
52 std::mutex config_lock;  // protects operations on |config|.
53 std::unique_ptr<config_t> config;
54 alarm_t* config_timer;
55 
56 using bluetooth::common::InitFlags;
57 
device_iot_config_has_section(const std::string & section)58 bool device_iot_config_has_section(const std::string& section) {
59   if (!InitFlags::IsDeviceIotConfigLoggingEnabled()) return false;
60 
61   CHECK(config != NULL);
62 
63   std::unique_lock<std::mutex> lock(config_lock);
64   return config_has_section(*config, section);
65 }
66 
device_iot_config_exist(const std::string & section,const std::string & key)67 bool device_iot_config_exist(const std::string& section,
68                              const std::string& key) {
69   if (!InitFlags::IsDeviceIotConfigLoggingEnabled()) return false;
70 
71   CHECK(config != NULL);
72 
73   std::unique_lock<std::mutex> lock(config_lock);
74   return config_has_key(*config, section, key);
75 }
76 
device_iot_config_get_int(const std::string & section,const std::string & key,int & value)77 bool device_iot_config_get_int(const std::string& section,
78                                const std::string& key, int& value) {
79   if (!InitFlags::IsDeviceIotConfigLoggingEnabled()) return false;
80 
81   CHECK(config != NULL);
82 
83   std::unique_lock<std::mutex> lock(config_lock);
84   bool ret = config_has_key(*config, section, key);
85   if (ret) value = config_get_int(*config, section, key, value);
86 
87   return ret;
88 }
89 
device_iot_config_set_int(const std::string & section,const std::string & key,int value)90 bool device_iot_config_set_int(const std::string& section,
91                                const std::string& key, int value) {
92   if (!InitFlags::IsDeviceIotConfigLoggingEnabled()) return false;
93 
94   CHECK(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)) return true;
100 
101   config_set_string(config.get(), section, key, value_str);
102   device_iot_config_save_async();
103 
104   return true;
105 }
106 
device_iot_config_int_add_one(const std::string & section,const std::string & key)107 bool device_iot_config_int_add_one(const std::string& section,
108                                    const std::string& key) {
109   if (!InitFlags::IsDeviceIotConfigLoggingEnabled()) return false;
110 
111   CHECK(config != NULL);
112 
113   int result = 0;
114   std::unique_lock<std::mutex> lock(config_lock);
115   result = config_get_int(*config, section, key, result);
116   if (result >= 0) {
117     result += 1;
118   } else {
119     result = 0;
120   }
121   config_set_int(config.get(), section, key, result);
122   device_iot_config_save_async();
123 
124   return true;
125 }
126 
device_iot_config_get_hex(const std::string & section,const std::string & key,int & value)127 bool device_iot_config_get_hex(const std::string& section,
128                                const std::string& key, int& value) {
129   if (!InitFlags::IsDeviceIotConfigLoggingEnabled()) return false;
130 
131   CHECK(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 (!InitFlags::IsDeviceIotConfigLoggingEnabled()) return false;
153 
154   CHECK(config != NULL);
155 
156   char value_str[32] = {0};
157   if (byte_num == 1)
158     snprintf(value_str, sizeof(value_str), "%02x", value);
159   else if (byte_num == 2)
160     snprintf(value_str, sizeof(value_str), "%04x", value);
161   else if (byte_num == 3)
162     snprintf(value_str, sizeof(value_str), "%06x", value);
163   else if (byte_num == 4)
164     snprintf(value_str, sizeof(value_str), "%08x", value);
165 
166   std::unique_lock<std::mutex> lock(config_lock);
167   if (device_iot_config_has_key_value(section, key, value_str)) return true;
168 
169   config_set_string(config.get(), section, key, value_str);
170   device_iot_config_save_async();
171 
172   return true;
173 }
174 
device_iot_config_set_hex_if_greater(const std::string & section,const std::string & key,int value,int byte_num)175 bool device_iot_config_set_hex_if_greater(const std::string& section,
176                                           const std::string& key, int value,
177                                           int byte_num) {
178   if (!InitFlags::IsDeviceIotConfigLoggingEnabled()) return false;
179 
180   int stored_value = 0;
181   bool ret = device_iot_config_get_hex(section, key, stored_value);
182   if (ret && stored_value >= value) return true;
183 
184   return device_iot_config_set_hex(section, key, value, byte_num);
185 }
186 
device_iot_config_get_str(const std::string & section,const std::string & key,char * value,int * size_bytes)187 bool device_iot_config_get_str(const std::string& section,
188                                const std::string& key, char* value,
189                                int* size_bytes) {
190   if (!InitFlags::IsDeviceIotConfigLoggingEnabled()) return false;
191 
192   CHECK(config != NULL);
193   CHECK(value != NULL);
194   CHECK(size_bytes != NULL);
195 
196   std::unique_lock<std::mutex> lock(config_lock);
197   const std::string* stored_value =
198       config_get_string(*config, section, key, NULL);
199 
200   if (!stored_value) return false;
201 
202   strlcpy(value, stored_value->c_str(), *size_bytes);
203   *size_bytes = strlen(value) + 1;
204 
205   return true;
206 }
207 
device_iot_config_set_str(const std::string & section,const std::string & key,const std::string & value)208 bool device_iot_config_set_str(const std::string& section,
209                                const std::string& key,
210                                const std::string& value) {
211   if (!InitFlags::IsDeviceIotConfigLoggingEnabled()) return false;
212 
213   CHECK(config != NULL);
214 
215   std::unique_lock<std::mutex> lock(config_lock);
216   if (device_iot_config_has_key_value(section, key, value)) return true;
217 
218   config_set_string(config.get(), section, key, value);
219   device_iot_config_save_async();
220 
221   return true;
222 }
223 
device_iot_config_get_bin(const std::string & section,const std::string & key,uint8_t * value,size_t * length)224 bool device_iot_config_get_bin(const std::string& section,
225                                const std::string& key, uint8_t* value,
226                                size_t* length) {
227   if (!InitFlags::IsDeviceIotConfigLoggingEnabled()) return false;
228 
229   CHECK(config != NULL);
230   CHECK(value != NULL);
231   CHECK(length != NULL);
232 
233   std::unique_lock<std::mutex> lock(config_lock);
234   const std::string* value_string =
235       config_get_string(*config, section, key, NULL);
236 
237   if (!value_string) return false;
238 
239   const char* value_str = value_string->c_str();
240 
241   size_t value_len = strlen(value_str);
242   if ((value_len % 2) != 0 || *length < (value_len / 2)) return false;
243 
244   for (size_t i = 0; i < value_len; ++i)
245     if (!isxdigit(value_str[i])) return false;
246 
247   for (*length = 0; *value_str; value_str += 2, *length += 1) {
248     errno = 0;
249     char* endptr = nullptr;
250     value[*length] = strtoul(value_str, &endptr, 16);
251     if (value_str == endptr) return false;
252     if (*endptr) return false;
253     if (errno) return false;
254   }
255 
256   return true;
257 }
258 
device_iot_config_get_bin_length(const std::string & section,const std::string & key)259 size_t device_iot_config_get_bin_length(const std::string& section,
260                                         const std::string& key) {
261   if (!InitFlags::IsDeviceIotConfigLoggingEnabled()) return 0;
262 
263   CHECK(config != NULL);
264 
265   std::unique_lock<std::mutex> lock(config_lock);
266   const std::string* value_str = config_get_string(*config, section, key, NULL);
267 
268   if (!value_str) return 0;
269 
270   size_t value_len = strlen(value_str->c_str());
271   return ((value_len % 2) != 0) ? 0 : (value_len / 2);
272 }
273 
device_iot_config_set_bin(const std::string & section,const std::string & key,const uint8_t * value,size_t length)274 bool device_iot_config_set_bin(const std::string& section,
275                                const std::string& key, const uint8_t* value,
276                                size_t length) {
277   if (!InitFlags::IsDeviceIotConfigLoggingEnabled()) return false;
278 
279   const char* lookup = "0123456789abcdef";
280 
281   CHECK(config != NULL);
282 
283   LOG_VERBOSE("Key = %s", key.c_str());
284   if (length > 0) CHECK(value != NULL);
285 
286   char* str = (char*)osi_calloc(length * 2 + 1);
287   if (str == NULL) {
288     LOG_ERROR("Unable to allocate a str.");
289     return false;
290   }
291 
292   for (size_t i = 0; i < length; ++i) {
293     str[(i * 2) + 0] = lookup[(value[i] >> 4) & 0x0F];
294     str[(i * 2) + 1] = lookup[value[i] & 0x0F];
295   }
296 
297   std::unique_lock<std::mutex> lock(config_lock);
298   if (device_iot_config_has_key_value(section, key, str)) {
299     osi_free(str);
300     return true;
301   }
302 
303   config_set_string(config.get(), section, key, str);
304   device_iot_config_save_async();
305 
306   osi_free(str);
307   return true;
308 }
309 
device_iot_config_remove(const std::string & section,const std::string & key)310 bool device_iot_config_remove(const std::string& section,
311                               const std::string& key) {
312   if (!InitFlags::IsDeviceIotConfigLoggingEnabled()) return false;
313 
314   CHECK(config != NULL);
315 
316   std::unique_lock<std::mutex> lock(config_lock);
317   return config_remove_key(config.get(), section, key);
318 }
319 
device_iot_config_flush(void)320 void device_iot_config_flush(void) {
321   if (!InitFlags::IsDeviceIotConfigLoggingEnabled()) return;
322 
323   CHECK(config != NULL);
324   CHECK(config_timer != NULL);
325 
326   int event = alarm_is_scheduled(config_timer) ? IOT_CONFIG_SAVE_TIMER_FIRED_EVT
327                                                : IOT_CONFIG_FLUSH_EVT;
328   LOG_VERBOSE("evt=%d", event);
329   alarm_cancel(config_timer);
330   device_iot_config_write(event, NULL);
331 }
332 
device_iot_config_clear(void)333 bool device_iot_config_clear(void) {
334   if (!InitFlags::IsDeviceIotConfigLoggingEnabled()) return true;
335 
336   CHECK(config != NULL);
337   CHECK(config_timer != NULL);
338 
339   LOG_INFO("");
340   alarm_cancel(config_timer);
341 
342   std::unique_lock<std::mutex> lock(config_lock);
343   config.reset();
344 
345   config = config_new_empty();
346   if (config == NULL) {
347     return false;
348   }
349 
350   bool ret = config_save(*config, IOT_CONFIG_FILE_PATH);
351   device_iot_config_source = RESET;
352   return ret;
353 }
354 
device_debug_iot_config_dump(int fd)355 void device_debug_iot_config_dump(int fd) {
356   if (!InitFlags::IsDeviceIotConfigLoggingEnabled()) return;
357 
358   dprintf(fd, "\nBluetooth Iot Config:\n");
359 
360   dprintf(fd, "  Config Source: ");
361   switch (device_iot_config_source) {
362     case NOT_LOADED:
363       dprintf(fd, "Not loaded\n");
364       break;
365     case ORIGINAL:
366       dprintf(fd, "Original file\n");
367       break;
368     case BACKUP:
369       dprintf(fd, "Backup file\n");
370       break;
371     case NEW_FILE:
372       dprintf(fd, "New file\n");
373       break;
374     case RESET:
375       dprintf(fd, "Reset file\n");
376       break;
377   }
378 
379   dprintf(fd, "  Devices loaded: %d\n", device_iot_config_devices_loaded);
380   dprintf(fd, "  File created/tagged: %s\n", device_iot_config_time_created);
381 }
382