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