1 /******************************************************************************
2  *
3  *  Copyright 2022 The Android Open Source Project
4  *
5  *  Licensed under the Apache License, Version 2.0 (the "License");
6  *  you may not use this file except in compliance with the License.
7  *  You may obtain a copy of the License at:
8  *
9  *  http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *  Unless required by applicable law or agreed to in writing, software
12  *  distributed under the License is distributed on an "AS IS" BASIS,
13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *  See the License for the specific language governing permissions and
15  *  limitations under the License.
16  *
17  ******************************************************************************/
18 
19 #define LOG_TAG "bt_bta_gattc"
20 
21 #include <base/strings/string_number_conversions.h>
22 #include <bluetooth/log.h>
23 #include <dirent.h>
24 #include <sys/stat.h>
25 
26 #include <string>
27 #include <vector>
28 
29 #include "bta/gatt/bta_gattc_int.h"
30 #include "gatt/database.h"
31 #include "os/log.h"
32 #include "stack/include/gattdefs.h"
33 #include "types/bluetooth/uuid.h"
34 
35 using namespace bluetooth;
36 
37 using gatt::StoredAttribute;
38 using std::string;
39 using std::vector;
40 
41 #ifdef TARGET_FLOSS
42 #define GATT_CACHE_PREFIX "/var/lib/bluetooth/gatt/gatt_cache_"
43 #define GATT_CACHE_VERSION 6
44 
45 #define GATT_HASH_MAX_SIZE 30
46 #define GATT_HASH_PATH_PREFIX "/var/lib/bluetooth/gatt/gatt_hash_"
47 #define GATT_HASH_PATH "/var/lib/bluetooth/gatt"
48 #define GATT_HASH_FILE_PREFIX "gatt_hash_"
49 #else
50 #define GATT_CACHE_PREFIX "/data/misc/bluetooth/gatt_cache_"
51 #define GATT_CACHE_VERSION 6
52 
53 #define GATT_HASH_MAX_SIZE 30
54 #define GATT_HASH_PATH_PREFIX "/data/misc/bluetooth/gatt_hash_"
55 #define GATT_HASH_PATH "/data/misc/bluetooth"
56 #define GATT_HASH_FILE_PREFIX "gatt_hash_"
57 #endif
58 
59 // Default expired time is 7 days
60 #define GATT_HASH_EXPIRED_TIME 604800
61 
62 static void bta_gattc_hash_remove_least_recently_used_if_possible();
63 
bta_gattc_generate_cache_file_name(char * buffer,size_t buffer_len,const RawAddress & bda)64 static void bta_gattc_generate_cache_file_name(char* buffer, size_t buffer_len,
65                                                const RawAddress& bda) {
66   snprintf(buffer, buffer_len, "%s%02x%02x%02x%02x%02x%02x", GATT_CACHE_PREFIX,
67            bda.address[0], bda.address[1], bda.address[2], bda.address[3],
68            bda.address[4], bda.address[5]);
69 }
70 
bta_gattc_generate_hash_file_name(char * buffer,size_t buffer_len,const Octet16 & hash)71 static void bta_gattc_generate_hash_file_name(char* buffer, size_t buffer_len,
72                                               const Octet16& hash) {
73   snprintf(buffer, buffer_len, "%s%s", GATT_HASH_PATH_PREFIX,
74            base::HexEncode(hash.data(), 16).c_str());
75 }
76 
77 static gatt::Database EMPTY_DB;
78 
79 /*******************************************************************************
80  *
81  * Function         bta_gattc_load_db
82  *
83  * Description      Load GATT database from storage.
84  *
85  * Parameter        fname: input file name
86  *
87  * Returns          non-empty GATT database on success, empty GATT database
88  *                  otherwise
89  *
90  ******************************************************************************/
bta_gattc_load_db(const char * fname)91 static gatt::Database bta_gattc_load_db(const char* fname) {
92   FILE* fd = fopen(fname, "rb");
93   if (!fd) {
94     log::error("can't open GATT cache file {} for reading, error: {}", fname,
95                strerror(errno));
96     return EMPTY_DB;
97   }
98 
99   uint16_t cache_ver = 0;
100   uint16_t num_attr = 0;
101 
102   if (fread(&cache_ver, sizeof(uint16_t), 1, fd) != 1) {
103     log::error("can't read GATT cache version from: {}", fname);
104     goto done;
105   }
106 
107   if (cache_ver != GATT_CACHE_VERSION) {
108     log::error("wrong GATT cache version: {}", fname);
109     goto done;
110   }
111 
112   if (fread(&num_attr, sizeof(uint16_t), 1, fd) != 1) {
113     log::error("can't read number of GATT attributes: {}", fname);
114     goto done;
115   }
116 
117   {
118     std::vector<StoredAttribute> attr(num_attr);
119 
120     if (fread(attr.data(), sizeof(StoredAttribute), num_attr, fd) != num_attr) {
121       log::error("can't read GATT attributes: {}", fname);
122       goto done;
123     }
124     fclose(fd);
125 
126     bool success = false;
127     gatt::Database result = gatt::Database::Deserialize(attr, &success);
128     return success ? result : EMPTY_DB;
129   }
130 
131 done:
132   fclose(fd);
133   return EMPTY_DB;
134 }
135 
136 /*******************************************************************************
137  *
138  * Function         bta_gattc_cache_load
139  *
140  * Description      Load GATT cache from storage for server.
141  *
142  * Parameter        bd_address: remote device address
143  *
144  * Returns          non-empty GATT database on success, empty GATT database
145  *                  otherwise
146  *
147  ******************************************************************************/
bta_gattc_cache_load(const RawAddress & server_bda)148 gatt::Database bta_gattc_cache_load(const RawAddress& server_bda) {
149   char fname[255] = {0};
150   bta_gattc_generate_cache_file_name(fname, sizeof(fname), server_bda);
151   return bta_gattc_load_db(fname);
152 }
153 
154 /*******************************************************************************
155  *
156  * Function         bta_gattc_hash_load
157  *
158  * Description      Load GATT cache from storage for server.
159  *
160  * Parameter        hash: 16-byte value
161  *
162  * Returns          non-empty GATT database on success, empty GATT database
163  *                  otherwise
164  *
165  ******************************************************************************/
bta_gattc_hash_load(const Octet16 & hash)166 gatt::Database bta_gattc_hash_load(const Octet16& hash) {
167   char fname[255] = {0};
168   bta_gattc_generate_hash_file_name(fname, sizeof(fname), hash);
169   return bta_gattc_load_db(fname);
170 }
171 
SerializeStoredAttribute(const StoredAttribute & attr,std::vector<uint8_t> & bytes)172 void StoredAttribute::SerializeStoredAttribute(const StoredAttribute& attr,
173                                                std::vector<uint8_t>& bytes) {
174   size_t original_size = bytes.size();
175   // handle
176   bytes.push_back(attr.handle & 0xff);
177   bytes.push_back(attr.handle >> 8);
178   auto uuid = attr.type.To128BitBE();
179   bytes.insert(bytes.cend(), uuid.cbegin(), uuid.cend());
180 
181   if (attr.type.Is16Bit()) {
182     switch (attr.type.As16Bit()) {
183       /* primary or secondary service definition */
184       case GATT_UUID_PRI_SERVICE:
185       case GATT_UUID_SEC_SERVICE:
186         uuid = attr.value.service.uuid.To128BitBE();
187         bytes.insert(bytes.cend(), uuid.cbegin(), uuid.cend());
188         bytes.push_back(attr.value.service.end_handle & 0xff);
189         bytes.push_back(attr.value.service.end_handle >> 8);
190         break;
191       case GATT_UUID_INCLUDE_SERVICE:
192         /* included service definition */
193         bytes.push_back(attr.value.included_service.handle & 0xff);
194         bytes.push_back(attr.value.included_service.handle >> 8);
195         bytes.push_back(attr.value.included_service.end_handle & 0xff);
196         bytes.push_back(attr.value.included_service.end_handle >> 8);
197         uuid = attr.value.included_service.uuid.To128BitBE();
198         bytes.insert(bytes.cend(), uuid.cbegin(), uuid.cend());
199         break;
200       case GATT_UUID_CHAR_DECLARE:
201         /* characteristic definition */
202         bytes.push_back(attr.value.characteristic.properties);
203         bytes.push_back(0);  // Padding byte
204         bytes.push_back(attr.value.characteristic.value_handle & 0xff);
205         bytes.push_back(attr.value.characteristic.value_handle >> 8);
206         uuid = attr.value.characteristic.uuid.To128BitBE();
207         bytes.insert(bytes.cend(), uuid.cbegin(), uuid.cend());
208         break;
209       case GATT_UUID_CHAR_EXT_PROP:
210         /* for descriptor we store value only for
211          * «Characteristic Extended Properties» */
212         bytes.push_back(attr.value.characteristic_extended_properties & 0xff);
213         bytes.push_back(attr.value.characteristic_extended_properties >> 8);
214         break;
215       default:
216         // log::verbose("Unhandled type UUID 0x{:04x}", attr.type.As16Bit());
217         break;
218     }
219   }
220   // padding
221   for (size_t i = bytes.size() - original_size;
222        i < StoredAttribute::kSizeOnDisk; i++) {
223     bytes.push_back(0);
224   }
225 }
226 
227 /*******************************************************************************
228  *
229  * Function         bta_gattc_store_db
230  *
231  * Description      Storess GATT db.
232  *
233  * Parameter        fname: output file name
234  *                  attr: attributes to save.
235  *
236  * Returns          true on success, false otherwise
237  *
238  ******************************************************************************/
bta_gattc_store_db(const char * fname,const std::vector<StoredAttribute> & attr)239 static bool bta_gattc_store_db(const char* fname,
240                                const std::vector<StoredAttribute>& attr) {
241   FILE* fd = fopen(fname, "wb");
242   if (!fd) {
243     log::error("can't open GATT cache file for writing: {}", fname);
244     return false;
245   }
246 
247   uint16_t cache_ver = GATT_CACHE_VERSION;
248   if (fwrite(&cache_ver, sizeof(uint16_t), 1, fd) != 1) {
249     log::error("can't write GATT cache version: {}", fname);
250     fclose(fd);
251     return false;
252   }
253 
254   uint16_t num_attr = attr.size();
255   if (fwrite(&num_attr, sizeof(uint16_t), 1, fd) != 1) {
256     log::error("can't write GATT cache attribute count: {}", fname);
257     fclose(fd);
258     return false;
259   }
260 
261   std::vector<uint8_t> db_bytes;
262   db_bytes.reserve(num_attr * StoredAttribute::kSizeOnDisk);
263   for (const auto attribute : attr) {
264     StoredAttribute::SerializeStoredAttribute(attribute, db_bytes);
265   }
266 
267   if (fwrite(db_bytes.data(), sizeof(uint8_t), db_bytes.size(), fd) !=
268       db_bytes.size()) {
269     log::error("can't write GATT cache attributes: {}", fname);
270     fclose(fd);
271     return false;
272   }
273 
274   fclose(fd);
275   return true;
276 }
277 
278 /*******************************************************************************
279  *
280  * Function         bta_gattc_cache_write
281  *
282  * Description      This callout function is executed by GATT when a server
283  *                  cache is available to save. Before calling this API, make
284  *                  sure the device is bonded. Otherwise you might get lots of
285  *                  address caches for unbonded devices.
286  *
287  * Parameter        server_bda: server bd address of this cache belongs to
288  *                  database: attributes to save.
289  * Returns
290  *
291  ******************************************************************************/
bta_gattc_cache_write(const RawAddress & server_bda,const gatt::Database & database)292 void bta_gattc_cache_write(const RawAddress& server_bda,
293                            const gatt::Database& database) {
294   char addr_file[255] = {0};
295   char hash_file[255] = {0};
296   Octet16 hash = database.Hash();
297   bta_gattc_generate_cache_file_name(addr_file, sizeof(addr_file), server_bda);
298   bta_gattc_generate_hash_file_name(hash_file, sizeof(hash_file), hash);
299 
300   bool result = bta_gattc_hash_write(hash, database);
301   // Only link addr_file to hash file when hash_file is created successfully.
302   if (result) {
303     bta_gattc_cache_link(server_bda, hash);
304   }
305 }
306 
307 /*******************************************************************************
308  *
309  * Function         bta_gattc_cache_link
310  *
311  * Description      Link address-database file to hash-database file
312  *
313  * Parameter        server_bda: server bd address of this cache belongs to
314  *                  hash: 16-byte value
315  *
316  * Returns          true on success, false otherwise
317  *
318  ******************************************************************************/
bta_gattc_cache_link(const RawAddress & server_bda,const Octet16 & hash)319 void bta_gattc_cache_link(const RawAddress& server_bda, const Octet16& hash) {
320   char addr_file[255] = {0};
321   char hash_file[255] = {0};
322   bta_gattc_generate_cache_file_name(addr_file, sizeof(addr_file), server_bda);
323   bta_gattc_generate_hash_file_name(hash_file, sizeof(hash_file), hash);
324 
325   unlink(addr_file);  // remove addr file first if the file exists
326   if (link(hash_file, addr_file) == -1) {
327     log::error("link {} to {}, errno={}", addr_file, hash_file, errno);
328   }
329 }
330 
331 /*******************************************************************************
332  *
333  * Function         bta_gattc_hash_write
334  *
335  * Description      This callout function is executed by GATT when a server
336  *                  cache is available to save for specific hash.
337  *
338  * Parameter        hash: 16-byte value
339  *                  database: gatt::Database instance.
340  *
341  * Returns          true on success, false otherwise
342  *
343  ******************************************************************************/
bta_gattc_hash_write(const Octet16 & hash,const gatt::Database & database)344 bool bta_gattc_hash_write(const Octet16& hash, const gatt::Database& database) {
345   char fname[255] = {0};
346   bta_gattc_generate_hash_file_name(fname, sizeof(fname), hash);
347   bta_gattc_hash_remove_least_recently_used_if_possible();
348   return bta_gattc_store_db(fname, database.Serialize());
349 }
350 
351 /*******************************************************************************
352  *
353  * Function         bta_gattc_cache_reset
354  *
355  * Description      This callout function is executed by GATTC to reset cache in
356  *                  application
357  *
358  * Parameter        server_bda: server bd address of this cache belongs to
359  *
360  * Returns          void.
361  *
362  ******************************************************************************/
bta_gattc_cache_reset(const RawAddress & server_bda)363 void bta_gattc_cache_reset(const RawAddress& server_bda) {
364   log::verbose("");
365   char fname[255] = {0};
366   bta_gattc_generate_cache_file_name(fname, sizeof(fname), server_bda);
367   unlink(fname);
368 }
369 
370 /*******************************************************************************
371  *
372  * Function         bta_gattc_hash_remove_least_recently_used_if_possible
373  *
374  * Description      When the max size reaches, find the oldest item and remove
375  *                  it if possible
376  *
377  * Parameter
378  *
379  * Returns          void
380  *
381  ******************************************************************************/
bta_gattc_hash_remove_least_recently_used_if_possible()382 static void bta_gattc_hash_remove_least_recently_used_if_possible() {
383   std::unique_ptr<DIR, decltype(&closedir)> dirp(opendir(GATT_HASH_PATH),
384                                                  &closedir);
385   if (dirp == nullptr) {
386     log::error("open dir error, dir={}", GATT_HASH_PATH);
387     return;
388   }
389 
390   time_t current_time = time(NULL);
391   time_t lru_time = current_time;
392   size_t count = 0;
393   string candidate_item;
394   vector<string> expired_items;
395 
396   log::debug("<-----------Start Local Hash Cache---------->");
397   dirent* dp;
398   while ((dp = readdir(dirp.get())) != nullptr) {
399     if (strncmp(".", dp->d_name, 1) == 0 || strncmp("..", dp->d_name, 2) == 0) {
400       continue;
401     }
402 
403     // pattern match: gatt_hash_
404     size_t fname_len = strlen(dp->d_name);
405     size_t pattern_len = strlen(GATT_HASH_FILE_PREFIX);
406     if (pattern_len > fname_len) {
407       continue;
408     }
409 
410     // check if the file name has gatt_hash_ as prefix
411     char tmp[255] = {0};
412     strncpy(tmp, dp->d_name, pattern_len);
413     if (strncmp(tmp, GATT_HASH_FILE_PREFIX, pattern_len) != 0) {
414       continue;
415     }
416 
417     // increase hash file count
418     count++;
419 
420     // generate the full path, in order to get the state of the file
421     snprintf(tmp, 255, "%s/%s", GATT_HASH_PATH, dp->d_name);
422 
423     struct stat buf;
424     int result = lstat(tmp, &buf);
425     log::debug("name={}, result={}, linknum={}, mtime={}", dp->d_name, result,
426                (unsigned long)buf.st_nlink, (unsigned long)buf.st_mtime);
427 
428     // if hard link count of the file is 1, it means no trusted device links to
429     // the inode. It is safe to be a candidate to be removed
430     if (buf.st_nlink == 1) {
431       if (buf.st_mtime < lru_time) {
432         lru_time = buf.st_mtime;
433         // Find the LRU candidate during for-loop itreation.
434         candidate_item.assign(tmp);
435       }
436 
437       if (buf.st_mtime + GATT_HASH_EXPIRED_TIME < current_time) {
438         // Add expired item.
439         expired_items.emplace_back(tmp);
440       }
441     }
442   }
443   log::debug("<-----------End Local Hash Cache------------>");
444 
445   // if the number of hash files exceeds the limit, remove the cadidate item.
446   if (count > GATT_HASH_MAX_SIZE && !candidate_item.empty()) {
447     unlink(candidate_item.c_str());
448     log::debug("delete hash file (size), name={}", candidate_item);
449   }
450 
451   // If there is any file expired, also delete it.
452   for (string expired_item : expired_items) {
453     unlink(expired_item.c_str());
454     log::debug("delete hash file (expired), name={}", expired_item);
455   }
456 }
457