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