1 /******************************************************************************
2  *
3  *  Copyright (C) 2016 The Linux Foundation
4  *  Copyright 2015 Google, Inc.
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 
20 #define LOG_TAG "bt_device_interop"
21 
22 #include "device/include/interop.h"
23 
24 #include <assert.h>
25 #include <bluetooth/log.h>
26 #include <ctype.h>
27 #include <fcntl.h>
28 #include <hardware/bluetooth.h>
29 #include <pthread.h>
30 #include <string.h>  // For memcmp
31 #include <sys/stat.h>
32 #include <unistd.h>
33 
34 #include <iostream>
35 #include <map>
36 #include <string>
37 #include <utility>
38 
39 #include "btcore/include/module.h"
40 #include "btif/include/btif_storage.h"
41 #include "device/include/interop_config.h"
42 #include "device/include/interop_database.h"
43 #include "os/log.h"
44 #include "osi/include/allocator.h"
45 #include "osi/include/compat.h"
46 #include "osi/include/config.h"
47 #include "osi/include/list.h"
48 #include "osi/include/osi.h"
49 #include "types/raw_address.h"
50 
51 using namespace bluetooth;
52 
53 #ifdef __ANDROID__
54 static const char* INTEROP_DYNAMIC_FILE_PATH =
55     "/data/misc/bluedroid/interop_database_dynamic.conf";
56 static const char* INTEROP_STATIC_FILE_PATH =
57     "/apex/com.android.btservices/etc/bluetooth/interop_database.conf";
58 #elif TARGET_FLOSS
59 #include <base/files/file_util.h>
60 
61 #include <filesystem>
62 
63 static const std::filesystem::path kDynamicConfigFileConfigFile =
64     std::filesystem::temp_directory_path() / "interop_database_dynamic.conf";
65 static const char* INTEROP_DYNAMIC_FILE_PATH =
66     kDynamicConfigFileConfigFile.c_str();
67 
68 static const char* INTEROP_STATIC_FILE_PATH =
69     "/var/lib/bluetooth/interop_database.conf";
70 #else  // !TARGET_FLOSS and !__ANDROID__
71 #include <base/files/file_util.h>
72 
73 #include <filesystem>
74 
75 static const std::filesystem::path kDynamicConfigFileConfigFile =
76     std::filesystem::temp_directory_path() / "interop_database_dynamic.conf";
77 static const char* INTEROP_DYNAMIC_FILE_PATH =
78     kDynamicConfigFileConfigFile.c_str();
79 
80 static const std::filesystem::path kStaticConfigFileConfigFile =
81     std::filesystem::temp_directory_path() / "interop_database.conf";
82 
83 static const char* INTEROP_STATIC_FILE_PATH =
84     kStaticConfigFileConfigFile.c_str();
85 #endif  // __ANDROID__
86 
87 #define CASE_RETURN_STR(const) \
88   case const:                  \
89     return #const;
90 
91 static list_t* interop_list = NULL;
92 
93 bool interop_is_initialized = false;
94 // protects operations on |interop_list|
95 pthread_mutex_t interop_list_lock;
96 
97 // protects operations on |config|
98 static pthread_mutex_t file_lock;
99 static std::unique_ptr<const config_t> config_static;
100 static std::unique_ptr<config_t> config_dynamic;
101 static const char* UNKNOWN_INTEROP_FEATURE = "UNKNOWN";
102 // map from feature name to feature id
103 static std::map<std::string, int> feature_name_id_map;
104 
105 // Macro used to find the total number of feature_types
106 #define NO_OF_FEATURES(x) (sizeof(x) / sizeof((x)[0]))
107 
108 #define SECTION_MAX_LENGTH (249)
109 #define KEY_MAX_LENGTH (249)
110 #define VALID_VNDR_PRDT_LEN (13)
111 #define VALID_MNFR_STR_LEN (6)
112 #define VALID_SSR_LAT_LEN (15)
113 #define VALID_VERSION_LEN (6)
114 #define VALID_LMP_VERSION_LEN (20)
115 #define VALID_ADDR_RANGE_LEN (35)
116 #define VENDOR_VALUE_SEPARATOR "-"
117 
118 #define ADDR_BASED "Address_Based"
119 #define ADDR_RANGE_BASED "Address_Range_Based"
120 #define NAME_BASED "Name_Based"
121 #define MNFR_BASED "Manufacturer_Based"
122 #define VNDR_PRDT_BASED "Vndr_Prdt_Based"
123 #define SSR_MAX_LAT_BASED "SSR_Max_Lat_Based"
124 #define VERSION_BASED "Version_Based"
125 #define LMP_VERSION_BASED "LMP_Version_Based"
126 
127 typedef struct {
128   char* key;
129   char* value;
130 } interop_entry_t;
131 
132 typedef struct {
133   char* name;
134   list_t* entries;
135 } interop_section_t;
136 
137 typedef struct {
138   RawAddress addr;
139   uint16_t max_lat;
140   interop_feature_t feature;
141 } interop_hid_ssr_max_lat_t;
142 
143 typedef struct {
144   uint16_t version;
145   interop_feature_t feature;
146 } interop_version_t;
147 
148 typedef struct {
149   RawAddress addr;
150   uint8_t lmp_ver;
151   uint16_t lmp_sub_ver;
152   interop_feature_t feature;
153 } interop_lmp_version_t;
154 
155 typedef enum {
156   INTEROP_BL_TYPE_ADDR = 0,
157   INTEROP_BL_TYPE_NAME,
158   INTEROP_BL_TYPE_MANUFACTURE,
159   INTEROP_BL_TYPE_VNDR_PRDT,
160   INTEROP_BL_TYPE_SSR_MAX_LAT,
161   INTEROP_BL_TYPE_VERSION,
162   INTEROP_BL_TYPE_LMP_VERSION,
163   INTEROP_BL_TYPE_ADDR_RANGE,
164 } interop_bl_type;
165 
166 typedef enum {
167   INTEROP_ENTRY_TYPE_STATIC = 1 << 0,
168   INTEROP_ENTRY_TYPE_DYNAMIC = 1 << 1
169 } interop_entry_type;
170 
171 typedef struct {
172   interop_bl_type bl_type;
173   interop_entry_type bl_entry_type;
174 
175   union {
176     interop_addr_entry_t addr_entry;
177     interop_name_entry_t name_entry;
178     interop_manufacturer_t mnfr_entry;
179     interop_hid_multitouch_t vnr_pdt_entry;
180     interop_hid_ssr_max_lat_t ssr_max_lat_entry;
181     interop_version_t version_entry;
182     interop_lmp_version_t lmp_version_entry;
183     interop_addr_range_entry_t addr_range_entry;
184   } entry_type;
185 
186 } interop_db_entry_t;
187 
188 namespace fmt {
189 template <>
190 struct formatter<interop_bl_type> : enum_formatter<interop_bl_type> {};
191 }  // namespace fmt
192 
193 static const char* interop_feature_string_(const interop_feature_t feature);
194 static void interop_free_entry_(void* data);
195 static void interop_lazy_init_(void);
196 
197 // Config related functions
198 static void interop_config_cleanup(void);
199 
200 // This function is used to initialize the interop list and load the entries
201 // from file
202 static void load_config();
203 static void interop_database_add_(interop_db_entry_t* db_entry, bool persist);
204 static bool interop_database_remove_(interop_db_entry_t* entry);
205 static bool interop_database_match(interop_db_entry_t* entry,
206                                    interop_db_entry_t** ret_entry,
207                                    interop_entry_type entry_type);
208 static void interop_config_flush(void);
209 static bool interop_config_remove(const std::string& section,
210                                   const std::string& key);
211 
212 // Interface functions
213 
interop_match_addr(const interop_feature_t feature,const RawAddress * addr)214 bool interop_match_addr(const interop_feature_t feature,
215                         const RawAddress* addr) {
216   log::assert_that(addr != nullptr, "assert failed: addr != nullptr");
217   return (interop_database_match_addr(feature, addr));
218 }
219 
interop_match_name(const interop_feature_t feature,const char * name)220 bool interop_match_name(const interop_feature_t feature, const char* name) {
221   log::assert_that(name != nullptr, "assert failed: name != nullptr");
222   return (interop_database_match_name(feature, name));
223 }
224 
interop_match_addr_or_name(const interop_feature_t feature,const RawAddress * addr,bt_status_t (* get_remote_device_property)(const RawAddress *,bt_property_t *))225 bool interop_match_addr_or_name(const interop_feature_t feature,
226                                 const RawAddress* addr,
227                                 bt_status_t (*get_remote_device_property)(
228                                     const RawAddress*, bt_property_t*)) {
229   log::assert_that(addr != nullptr, "assert failed: addr != nullptr");
230   log::assert_that(get_remote_device_property != nullptr,
231                    "assert failed: get_remote_device_property != nullptr");
232 
233   bt_bdname_t bdname;
234   bt_property_t prop_name;
235 
236   if (interop_match_addr(feature, addr)) return true;
237 
238   BTIF_STORAGE_FILL_PROPERTY(&prop_name, BT_PROPERTY_BDNAME,
239                              sizeof(bt_bdname_t), bdname.name);
240 
241   if (get_remote_device_property(addr, &prop_name) != BT_STATUS_SUCCESS)
242     return false;
243   if (strlen((const char*)bdname.name) == 0) return false;
244 
245   return interop_match_name(feature, (const char*)bdname.name);
246 }
247 
interop_match_manufacturer(const interop_feature_t feature,uint16_t manufacturer)248 bool interop_match_manufacturer(const interop_feature_t feature,
249                                 uint16_t manufacturer) {
250   return (interop_database_match_manufacturer(feature, manufacturer));
251 }
252 
interop_match_vendor_product_ids(const interop_feature_t feature,uint16_t vendor_id,uint16_t product_id)253 bool interop_match_vendor_product_ids(const interop_feature_t feature,
254                                       uint16_t vendor_id, uint16_t product_id) {
255   return interop_database_match_vndr_prdt(feature, vendor_id, product_id);
256 }
257 
interop_match_addr_get_max_lat(const interop_feature_t feature,const RawAddress * addr,uint16_t * max_lat)258 bool interop_match_addr_get_max_lat(const interop_feature_t feature,
259                                     const RawAddress* addr, uint16_t* max_lat) {
260   return interop_database_match_addr_get_max_lat(feature, addr, max_lat);
261 }
262 
interop_database_add(const uint16_t feature,const RawAddress * addr,size_t length)263 void interop_database_add(const uint16_t feature, const RawAddress* addr,
264                           size_t length) {
265   log::assert_that(addr != nullptr, "assert failed: addr != nullptr");
266   log::assert_that(length > 0, "assert failed: length > 0");
267   log::assert_that(length < sizeof(RawAddress),
268                    "assert failed: length < sizeof(RawAddress)");
269   interop_database_add_addr(feature, addr, length);
270 }
271 
interop_database_clear()272 void interop_database_clear() {
273   log::debug("interop_is_initialized: {} interop_list: {}",
274              interop_is_initialized, fmt::ptr(interop_list));
275 
276   if (interop_is_initialized && interop_list) {
277     for (int feature = BEGINNING_OF_INTEROP_LIST;
278          feature != END_OF_INTEROP_LIST; feature++) {
279       interop_database_remove_feature((interop_feature_t)feature);
280     }
281   }
282 }
283 
interop_init_feature_name_id_map()284 static void interop_init_feature_name_id_map() {
285   log::debug("");
286 
287   feature_name_id_map.clear();
288 
289   int feature;
290 
291   for (feature = BEGINNING_OF_INTEROP_LIST; feature < END_OF_INTEROP_LIST;
292        feature++) {
293     const char* feature_name =
294         interop_feature_string_((interop_feature_t)feature);
295     if (!strcmp(UNKNOWN_INTEROP_FEATURE, feature_name)) continue;
296 
297     feature_name_id_map.insert({feature_name, feature});
298   }
299 }
300 
301 // Module life-cycle functions
interop_init(void)302 static future_t* interop_init(void) {
303   interop_init_feature_name_id_map();
304 
305   interop_lazy_init_();
306   interop_is_initialized = true;
307   return future_new_immediate(FUTURE_SUCCESS);
308 }
309 
interop_clean_up(void)310 static future_t* interop_clean_up(void) {
311   pthread_mutex_lock(&interop_list_lock);
312   list_free(interop_list);
313   interop_list = NULL;
314   interop_is_initialized = false;
315   pthread_mutex_unlock(&interop_list_lock);
316   pthread_mutex_destroy(&interop_list_lock);
317   interop_config_cleanup();
318 
319   return future_new_immediate(FUTURE_SUCCESS);
320 }
321 
322 EXPORT_SYMBOL module_t interop_module = {
323     .name = INTEROP_MODULE,
324     .init = interop_init,
325     .start_up = NULL,
326     .shut_down = NULL,
327     .clean_up = interop_clean_up,
328     .dependencies = {NULL},
329 };
330 
331 // Local functions
332 
interop_feature_string_(const interop_feature_t feature)333 static const char* interop_feature_string_(const interop_feature_t feature) {
334   switch (feature) {
335     CASE_RETURN_STR(INTEROP_DISABLE_LE_SECURE_CONNECTIONS)
336     CASE_RETURN_STR(INTEROP_AUTO_RETRY_PAIRING)
337     CASE_RETURN_STR(INTEROP_DISABLE_ABSOLUTE_VOLUME)
338     CASE_RETURN_STR(INTEROP_DISABLE_AUTO_PAIRING)
339     CASE_RETURN_STR(INTEROP_KEYBOARD_REQUIRES_FIXED_PIN)
340     CASE_RETURN_STR(INTEROP_2MBPS_LINK_ONLY)
341     CASE_RETURN_STR(INTEROP_HID_PREF_CONN_SUP_TIMEOUT_3S)
342     CASE_RETURN_STR(INTEROP_GATTC_NO_SERVICE_CHANGED_IND)
343     CASE_RETURN_STR(INTEROP_DISABLE_SDP_AFTER_PAIRING)
344     CASE_RETURN_STR(INTEROP_DISABLE_AUTH_FOR_HID_POINTING)
345     CASE_RETURN_STR(INTEROP_REMOVE_HID_DIG_DESCRIPTOR)
346     CASE_RETURN_STR(INTEROP_DISABLE_SNIFF_DURING_SCO)
347     CASE_RETURN_STR(INTEROP_INCREASE_AG_CONN_TIMEOUT)
348     CASE_RETURN_STR(INTEROP_DISABLE_LE_CONN_PREFERRED_PARAMS)
349     CASE_RETURN_STR(INTEROP_DISABLE_AAC_CODEC)
350     CASE_RETURN_STR(INTEROP_DISABLE_AAC_VBR_CODEC)
351     CASE_RETURN_STR(INTEROP_DYNAMIC_ROLE_SWITCH)
352     CASE_RETURN_STR(INTEROP_DISABLE_ROLE_SWITCH)
353     CASE_RETURN_STR(INTEROP_DISABLE_ROLE_SWITCH_POLICY)
354     CASE_RETURN_STR(INTEROP_HFP_1_7_DENYLIST)
355     CASE_RETURN_STR(INTEROP_ADV_PBAP_VER_1_1)
356     CASE_RETURN_STR(INTEROP_UPDATE_HID_SSR_MAX_LAT)
357     CASE_RETURN_STR(INTEROP_DISABLE_AVDTP_RECONFIGURE)
358     CASE_RETURN_STR(INTEROP_DISABLE_HF_INDICATOR)
359     CASE_RETURN_STR(INTEROP_DISABLE_LE_CONN_UPDATES)
360     CASE_RETURN_STR(INTEROP_DELAY_SCO_FOR_MT_CALL)
361     CASE_RETURN_STR(INTEROP_DISABLE_CODEC_NEGOTIATION)
362     CASE_RETURN_STR(INTEROP_DISABLE_PLAYER_APPLICATION_SETTING_CMDS)
363     CASE_RETURN_STR(INTEROP_ENABLE_AAC_CODEC)
364     CASE_RETURN_STR(INTEROP_DISABLE_CONNECTION_AFTER_COLLISION)
365     CASE_RETURN_STR(INTEROP_AVRCP_BROWSE_OPEN_CHANNEL_COLLISION)
366     CASE_RETURN_STR(INTEROP_ADV_PBAP_VER_1_2)
367     CASE_RETURN_STR(INTEROP_DISABLE_PCE_SDP_AFTER_PAIRING)
368     CASE_RETURN_STR(INTEROP_DISABLE_SNIFF_LINK_DURING_SCO)
369     CASE_RETURN_STR(INTEROP_DISABLE_SNIFF_DURING_CALL)
370     CASE_RETURN_STR(INTEROP_HID_HOST_LIMIT_SNIFF_INTERVAL)
371     CASE_RETURN_STR(INTEROP_DISABLE_REFRESH_ACCEPT_SIG_TIMER)
372     CASE_RETURN_STR(INTEROP_SKIP_INCOMING_STATE)
373     CASE_RETURN_STR(INTEROP_NOT_UPDATE_AVRCP_PAUSED_TO_REMOTE)
374     CASE_RETURN_STR(INTEROP_PHONE_POLICY_INCREASED_DELAY_CONNECT_OTHER_PROFILES)
375     CASE_RETURN_STR(INTEROP_PHONE_POLICY_REDUCED_DELAY_CONNECT_OTHER_PROFILES)
376     CASE_RETURN_STR(INTEROP_HFP_FAKE_INCOMING_CALL_INDICATOR)
377     CASE_RETURN_STR(INTEROP_HFP_SEND_CALL_INDICATORS_BACK_TO_BACK)
378     CASE_RETURN_STR(INTEROP_SETUP_SCO_WITH_NO_DELAY_AFTER_SLC_DURING_CALL)
379     CASE_RETURN_STR(INTEROP_ENABLE_PREFERRED_CONN_PARAMETER)
380     CASE_RETURN_STR(INTEROP_RETRY_SCO_AFTER_REMOTE_REJECT_SCO)
381     CASE_RETURN_STR(INTEROP_DELAY_SCO_FOR_MO_CALL)
382     CASE_RETURN_STR(INTEROP_CHANGE_HID_VID_PID)
383     CASE_RETURN_STR(END_OF_INTEROP_LIST)
384     CASE_RETURN_STR(INTEROP_HFP_1_8_DENYLIST)
385     CASE_RETURN_STR(INTEROP_DISABLE_ROLE_SWITCH_DURING_CONNECTION)
386     CASE_RETURN_STR(INTEROP_DISABLE_NAME_REQUEST)
387     CASE_RETURN_STR(INTEROP_AVRCP_1_4_ONLY)
388     CASE_RETURN_STR(INTEROP_DISABLE_SNIFF)
389     CASE_RETURN_STR(INTEROP_DISABLE_AVDTP_SUSPEND)
390     CASE_RETURN_STR(INTEROP_SLC_SKIP_BIND_COMMAND)
391     CASE_RETURN_STR(INTEROP_AVRCP_1_3_ONLY)
392     CASE_RETURN_STR(INTEROP_DISABLE_ROBUST_CACHING);
393     CASE_RETURN_STR(INTEROP_HFP_1_7_ALLOWLIST);
394     CASE_RETURN_STR(INTEROP_HFP_1_9_ALLOWLIST);
395     CASE_RETURN_STR(INTEROP_IGNORE_DISC_BEFORE_SIGNALLING_TIMEOUT);
396     CASE_RETURN_STR(INTEROP_SUSPEND_ATT_TRAFFIC_DURING_PAIRING);
397     CASE_RETURN_STR(INTEROP_INSERT_CALL_WHEN_SCO_START);
398     CASE_RETURN_STR(INTEROP_DELAY_AUTH);
399     CASE_RETURN_STR(INTEROP_MULTIPLE_HOGP_SERVICE_CHOOSE_THIRD);
400     CASE_RETURN_STR(INTEROP_A2DP_SKIP_SDP_DURING_RECONNECTION);
401   }
402   return UNKNOWN_INTEROP_FEATURE;
403 }
404 
interop_free_entry_(void * data)405 static void interop_free_entry_(void* data) {
406   interop_db_entry_t* entry = (interop_db_entry_t*)data;
407   osi_free(entry);
408 }
409 
interop_lazy_init_(void)410 static void interop_lazy_init_(void) {
411   pthread_mutex_init(&interop_list_lock, NULL);
412   if (interop_list == NULL) {
413     interop_list = list_new(interop_free_entry_);
414     load_config();
415   }
416 }
417 
418 // interop config related functions
419 
interop_config_init(void)420 static int interop_config_init(void) {
421   struct stat sts;
422   pthread_mutex_init(&file_lock, NULL);
423   pthread_mutex_lock(&file_lock);
424 
425   if (!stat(INTEROP_STATIC_FILE_PATH, &sts) && sts.st_size) {
426     if (!(config_static = config_new(INTEROP_STATIC_FILE_PATH))) {
427       log::warn("unable to load static config file for : {}",
428                 INTEROP_STATIC_FILE_PATH);
429     }
430   }
431   if (!config_static && !(config_static = config_new_empty())) {
432     goto error;
433   }
434 
435   if (!stat(INTEROP_DYNAMIC_FILE_PATH, &sts) && sts.st_size) {
436     if (!(config_dynamic = config_new(INTEROP_DYNAMIC_FILE_PATH))) {
437       log::warn("unable to load dynamic config file for : {}",
438                 INTEROP_DYNAMIC_FILE_PATH);
439     }
440   }
441   if (!config_dynamic && !(config_dynamic = config_new_empty())) {
442     goto error;
443   }
444   pthread_mutex_unlock(&file_lock);
445   return 0;
446 
447 error:
448   config_static.reset();
449   config_dynamic.reset();
450   pthread_mutex_unlock(&file_lock);
451   return -1;
452 }
453 
interop_config_flush(void)454 static void interop_config_flush(void) {
455   log::assert_that(config_dynamic.get() != NULL,
456                    "assert failed: config_dynamic.get() != NULL");
457 
458   pthread_mutex_lock(&file_lock);
459   config_save(*config_dynamic, INTEROP_DYNAMIC_FILE_PATH);
460   pthread_mutex_unlock(&file_lock);
461 }
462 
interop_config_remove(const std::string & section,const std::string & key)463 static bool interop_config_remove(const std::string& section,
464                                   const std::string& key) {
465   log::assert_that(config_dynamic.get() != NULL,
466                    "assert failed: config_dynamic.get() != NULL");
467 
468   pthread_mutex_lock(&file_lock);
469   bool ret = config_remove_key(config_dynamic.get(), section, key);
470   pthread_mutex_unlock(&file_lock);
471 
472   return ret;
473 }
474 
interop_config_remove_section(const std::string & section)475 static bool interop_config_remove_section(const std::string& section) {
476   log::assert_that(config_dynamic.get() != NULL,
477                    "assert failed: config_dynamic.get() != NULL");
478 
479   pthread_mutex_lock(&file_lock);
480   bool ret = config_remove_section(config_dynamic.get(), section);
481   pthread_mutex_unlock(&file_lock);
482 
483   return ret;
484 }
485 
interop_config_set_str(const std::string & section,const std::string & key,const std::string & value)486 static bool interop_config_set_str(const std::string& section,
487                                    const std::string& key,
488                                    const std::string& value) {
489   log::assert_that(config_dynamic.get() != NULL,
490                    "assert failed: config_dynamic.get() != NULL");
491 
492   pthread_mutex_lock(&file_lock);
493   config_set_string(config_dynamic.get(), section, key, value);
494   pthread_mutex_unlock(&file_lock);
495 
496   return true;
497 }
498 
interop_feature_name_to_feature_id(const char * feature_name)499 int interop_feature_name_to_feature_id(const char* feature_name) {
500   if (feature_name == NULL) {
501     return -1;
502   }
503 
504   auto it = feature_name_id_map.find(std::string(feature_name));
505   if (it == feature_name_id_map.end()) {
506     log::warn("feature does not exist: {}", feature_name);
507     return -1;
508   }
509 
510   return it->second;
511 }
512 
interop_config_add_or_remove(interop_db_entry_t * db_entry,bool add)513 static bool interop_config_add_or_remove(interop_db_entry_t* db_entry,
514                                          bool add) {
515   bool status = true;
516   std::string key;
517   std::string value;
518   interop_feature_t feature;
519 
520   // add it to the config file as well
521   switch (db_entry->bl_type) {
522     case INTEROP_BL_TYPE_ADDR: {
523       interop_addr_entry_t addr_entry = db_entry->entry_type.addr_entry;
524 
525       const std::string bdstr = addr_entry.addr.ToColonSepHexString().substr(
526           0, addr_entry.length * 3 - 1);
527 
528       feature = db_entry->entry_type.addr_entry.feature;
529       key.assign(bdstr);
530       value.assign(ADDR_BASED);
531 
532       break;
533     }
534     case INTEROP_BL_TYPE_NAME: {
535       feature = db_entry->entry_type.name_entry.feature;
536       key.assign(db_entry->entry_type.name_entry.name);
537       value.assign(NAME_BASED);
538 
539       break;
540     }
541     case INTEROP_BL_TYPE_MANUFACTURE: {
542       char m_facturer[KEY_MAX_LENGTH] = {'\0'};
543       snprintf(m_facturer, sizeof(m_facturer), "0x%04x",
544                db_entry->entry_type.mnfr_entry.manufacturer);
545 
546       feature = db_entry->entry_type.mnfr_entry.feature;
547       key.assign(m_facturer);
548       value.assign(MNFR_BASED);
549 
550       break;
551     }
552     case INTEROP_BL_TYPE_VNDR_PRDT: {
553       char m_vnr_pdt[KEY_MAX_LENGTH] = {'\0'};
554       snprintf(m_vnr_pdt, sizeof(m_vnr_pdt), "0x%04x-0x%04x",
555                db_entry->entry_type.vnr_pdt_entry.vendor_id,
556                db_entry->entry_type.vnr_pdt_entry.product_id);
557 
558       feature = db_entry->entry_type.vnr_pdt_entry.feature;
559       key.assign(m_vnr_pdt);
560       value.assign(VNDR_PRDT_BASED);
561 
562       break;
563     }
564     case INTEROP_BL_TYPE_SSR_MAX_LAT: {
565       interop_hid_ssr_max_lat_t ssr_entry =
566           db_entry->entry_type.ssr_max_lat_entry;
567       char m_ssr_max_lat[KEY_MAX_LENGTH] = {'\0'};
568 
569       const std::string bdstr =
570           ssr_entry.addr.ToColonSepHexString().substr(0, 3 * 3 - 1);
571 
572       snprintf(m_ssr_max_lat, sizeof(m_ssr_max_lat), "%s-0x%04x", bdstr.c_str(),
573                db_entry->entry_type.ssr_max_lat_entry.max_lat);
574 
575       feature = db_entry->entry_type.ssr_max_lat_entry.feature;
576       key.assign(m_ssr_max_lat);
577       value.assign(SSR_MAX_LAT_BASED);
578 
579       break;
580     }
581     case INTEROP_BL_TYPE_VERSION: {
582       char m_version[KEY_MAX_LENGTH] = {'\0'};
583       snprintf(m_version, sizeof(m_version), "0x%04x",
584                db_entry->entry_type.version_entry.version);
585 
586       feature = db_entry->entry_type.version_entry.feature;
587       key.assign(m_version);
588       value.assign(VERSION_BASED);
589 
590       break;
591     }
592     case INTEROP_BL_TYPE_LMP_VERSION: {
593       interop_lmp_version_t lmp_version_entry =
594           db_entry->entry_type.lmp_version_entry;
595       char m_lmp_version[KEY_MAX_LENGTH] = {'\0'};
596       const std::string bdstr =
597           lmp_version_entry.addr.ToColonSepHexString().substr(0, 3 * 3 - 1);
598 
599       snprintf(m_lmp_version, sizeof(m_lmp_version), "%s-0x%02x-0x%04x",
600                bdstr.c_str(), db_entry->entry_type.lmp_version_entry.lmp_ver,
601                db_entry->entry_type.lmp_version_entry.lmp_sub_ver);
602 
603       feature = db_entry->entry_type.lmp_version_entry.feature;
604       key.assign(m_lmp_version);
605       value.assign(LMP_VERSION_BASED);
606 
607       break;
608     }
609     default:
610       log::error("bl_type: {} not handled", db_entry->bl_type);
611       status = false;
612       break;
613   }
614 
615   if (status) {
616     if (add) {
617       interop_config_set_str(interop_feature_string_(feature), key, value);
618     } else {
619       interop_config_remove(interop_feature_string_(feature), key);
620     }
621     interop_config_flush();
622   }
623 
624   return status;
625 }
626 
interop_database_add_(interop_db_entry_t * db_entry,bool persist)627 static void interop_database_add_(interop_db_entry_t* db_entry, bool persist) {
628   interop_db_entry_t* ret_entry = NULL;
629   bool match_found =
630       interop_database_match(db_entry, &ret_entry,
631                              (interop_entry_type)(INTEROP_ENTRY_TYPE_STATIC |
632                                                   INTEROP_ENTRY_TYPE_DYNAMIC));
633 
634   if (match_found) {
635     // return as the entry is already present
636     log::debug("Entry is already present in the list");
637     return;
638   }
639 
640   pthread_mutex_lock(&interop_list_lock);
641 
642   if (interop_list) {
643     list_append(interop_list, db_entry);
644   }
645 
646   pthread_mutex_unlock(&interop_list_lock);
647 
648   if (!persist) {
649     // return if the persist option is not set
650     return;
651   }
652 
653   interop_config_add_or_remove(db_entry, true);
654 }
655 
interop_database_match(interop_db_entry_t * entry,interop_db_entry_t ** ret_entry,interop_entry_type entry_type)656 static bool interop_database_match(interop_db_entry_t* entry,
657                                    interop_db_entry_t** ret_entry,
658                                    interop_entry_type entry_type) {
659   log::assert_that(entry != nullptr, "assert failed: entry != nullptr");
660   bool found = false;
661   pthread_mutex_lock(&interop_list_lock);
662   if (interop_list == NULL || list_length(interop_list) == 0) {
663     pthread_mutex_unlock(&interop_list_lock);
664     return false;
665   }
666 
667   const list_node_t* node = list_begin(interop_list);
668 
669   while (node != list_end(interop_list)) {
670     interop_db_entry_t* db_entry = (interop_db_entry_t*)list_node(node);
671     log::assert_that(db_entry != nullptr, "assert failed: db_entry != nullptr");
672 
673     if (entry->bl_type != db_entry->bl_type) {
674       node = list_next(node);
675       continue;
676     }
677 
678     if ((entry_type == INTEROP_ENTRY_TYPE_STATIC) ||
679         (entry_type == INTEROP_ENTRY_TYPE_DYNAMIC)) {
680       if (entry->bl_entry_type != db_entry->bl_entry_type) {
681         node = list_next(node);
682         continue;
683       }
684     }
685 
686     switch (db_entry->bl_type) {
687       case INTEROP_BL_TYPE_ADDR: {
688         interop_addr_entry_t* src = &entry->entry_type.addr_entry;
689         interop_addr_entry_t* cur = &db_entry->entry_type.addr_entry;
690         if ((src->feature == cur->feature) &&
691             (!memcmp(&src->addr, &cur->addr, cur->length))) {
692           /* cur len is used to remove src entry from config file, when
693            * interop_database_remove_addr is called. */
694           src->length = cur->length;
695           found = true;
696         }
697         break;
698       }
699       case INTEROP_BL_TYPE_NAME: {
700         interop_name_entry_t* src = &entry->entry_type.name_entry;
701         interop_name_entry_t* cur = &db_entry->entry_type.name_entry;
702 
703         if ((src->feature == cur->feature) &&
704             (strcasestr(src->name, cur->name) == src->name)) {
705           found = true;
706         }
707         break;
708       }
709       case INTEROP_BL_TYPE_MANUFACTURE: {
710         interop_manufacturer_t* src = &entry->entry_type.mnfr_entry;
711         interop_manufacturer_t* cur = &db_entry->entry_type.mnfr_entry;
712 
713         if (src->feature == cur->feature &&
714             src->manufacturer == cur->manufacturer) {
715           found = true;
716         }
717         break;
718       }
719       case INTEROP_BL_TYPE_VNDR_PRDT: {
720         interop_hid_multitouch_t* src = &entry->entry_type.vnr_pdt_entry;
721         interop_hid_multitouch_t* cur = &db_entry->entry_type.vnr_pdt_entry;
722 
723         if ((src->feature == cur->feature) &&
724             (src->vendor_id == cur->vendor_id) &&
725             (src->product_id == cur->product_id)) {
726           found = true;
727         }
728         break;
729       }
730       case INTEROP_BL_TYPE_SSR_MAX_LAT: {
731         interop_hid_ssr_max_lat_t* src = &entry->entry_type.ssr_max_lat_entry;
732         interop_hid_ssr_max_lat_t* cur =
733             &db_entry->entry_type.ssr_max_lat_entry;
734 
735         if ((src->feature == cur->feature) &&
736             !memcmp(&src->addr, &cur->addr, 3)) {
737           found = true;
738         }
739         break;
740       }
741       case INTEROP_BL_TYPE_VERSION: {
742         interop_version_t* src = &entry->entry_type.version_entry;
743         interop_version_t* cur = &db_entry->entry_type.version_entry;
744 
745         if ((src->feature == cur->feature) && (src->version == cur->version)) {
746           found = true;
747         }
748         break;
749       }
750       case INTEROP_BL_TYPE_LMP_VERSION: {
751         interop_lmp_version_t* src = &entry->entry_type.lmp_version_entry;
752         interop_lmp_version_t* cur = &db_entry->entry_type.lmp_version_entry;
753 
754         if ((src->feature == cur->feature) &&
755             (!memcmp(&src->addr, &cur->addr, 3))) {
756           found = true;
757         }
758         break;
759       }
760       case INTEROP_BL_TYPE_ADDR_RANGE: {
761         interop_addr_range_entry_t* src = &entry->entry_type.addr_range_entry;
762         interop_addr_range_entry_t* cur =
763             &db_entry->entry_type.addr_range_entry;
764 
765         // src->addr_start has the actual address, which need to be searched in
766         // the range
767         if ((src->feature == cur->feature) &&
768             (src->addr_start >= cur->addr_start) &&
769             (src->addr_start <= cur->addr_end)) {
770           found = true;
771         }
772         break;
773       }
774       default:
775         log::error("bl_type: {} not handled", db_entry->bl_type);
776         break;
777     }
778 
779     if (found && ret_entry) {
780       *ret_entry = db_entry;
781       break;
782     }
783     node = list_next(node);
784   }
785   pthread_mutex_unlock(&interop_list_lock);
786   return found;
787 }
788 
interop_database_remove_(interop_db_entry_t * entry)789 static bool interop_database_remove_(interop_db_entry_t* entry) {
790   interop_db_entry_t* ret_entry = NULL;
791 
792   if (!interop_database_match(
793           entry, &ret_entry,
794           (interop_entry_type)(INTEROP_ENTRY_TYPE_DYNAMIC))) {
795     log::error("Entry not found in the list");
796     return false;
797   }
798 
799   // first remove it from linked list
800   pthread_mutex_lock(&interop_list_lock);
801   list_remove(interop_list, (void*)ret_entry);
802   pthread_mutex_unlock(&interop_list_lock);
803 
804   return interop_config_add_or_remove(entry, false);
805 }
806 
trim(char * str)807 static char* trim(char* str) {
808   while (isspace(*str)) ++str;
809 
810   if (!*str) return str;
811 
812   char* end_str = str + strlen(str) - 1;
813   while (end_str > str && isspace(*end_str)) --end_str;
814 
815   end_str[1] = '\0';
816   return str;
817 }
818 
token_to_ul(char * token,uint16_t * ul)819 bool token_to_ul(char* token, uint16_t* ul) {
820   char* e;
821   bool ret_value = false;
822 
823   token = trim(token);
824   errno = 0;
825   *ul = (uint16_t)strtoul(token, &e, 16);
826   if ((e != NULL) && errno != EINVAL && errno != ERANGE) ret_value = true;
827   return ret_value;
828 }
829 
get_vendor_product_id(char * vendorstr,uint16_t * vendor,uint16_t * product)830 static bool get_vendor_product_id(char* vendorstr, uint16_t* vendor,
831                                   uint16_t* product) {
832   char* token;
833   char* saveptr = NULL;
834   bool ret_value = false;
835 
836   if ((token = strtok_r(vendorstr, VENDOR_VALUE_SEPARATOR, &saveptr)) != NULL) {
837     ret_value = token_to_ul(token, vendor);
838   }
839 
840   if (ret_value &&
841       (token = strtok_r(NULL, VENDOR_VALUE_SEPARATOR, &saveptr)) != NULL) {
842     ret_value = token_to_ul(token, product);
843   }
844   return ret_value;
845 }
846 
get_addr_maxlat(char * str,char * bdaddrstr,uint16_t * max_lat)847 static bool get_addr_maxlat(char* str, char* bdaddrstr, uint16_t* max_lat) {
848   char* token;
849   char* saveptr = NULL;
850   bool ret_value = false;
851 
852   if ((token = strtok_r(str, VENDOR_VALUE_SEPARATOR, &saveptr)) != NULL) {
853     trim(token);
854     strlcpy(bdaddrstr, token, KEY_MAX_LENGTH);
855   } else {
856     return false;
857   }
858 
859   if ((token = strtok_r(NULL, VENDOR_VALUE_SEPARATOR, &saveptr)) != NULL) {
860     ret_value = token_to_ul(token, max_lat);
861   }
862   return ret_value;
863 }
864 
get_addr_range(char * str,RawAddress * addr_start,RawAddress * addr_end)865 static bool get_addr_range(char* str, RawAddress* addr_start,
866                            RawAddress* addr_end) {
867   char* token;
868   char* saveptr = NULL;
869   bool ret_value = false;
870   char addr_start_str[18] = {'\0'};
871   char addr_end_str[18] = {'\0'};
872 
873   if ((token = strtok_r(str, VENDOR_VALUE_SEPARATOR, &saveptr)) != NULL) {
874     trim(token);
875     strlcpy(addr_start_str, token, 18);
876     if (!RawAddress::FromString(addr_start_str, *addr_start)) return false;
877   } else {
878     return false;
879   }
880 
881   if ((token = strtok_r(NULL, VENDOR_VALUE_SEPARATOR, &saveptr)) != NULL) {
882     trim(token);
883     strlcpy(addr_end_str, token, 18);
884     if (RawAddress::FromString(addr_end_str, *addr_end)) ret_value = true;
885   }
886   return ret_value;
887 }
888 
get_addr_lmp_ver(char * str,char * bdaddrstr,uint8_t * lmp_ver,uint16_t * lmp_sub_ver)889 static bool get_addr_lmp_ver(char* str, char* bdaddrstr, uint8_t* lmp_ver,
890                              uint16_t* lmp_sub_ver) {
891   char* token;
892   char* saveptr = NULL;
893   char* e;
894 
895   if ((token = strtok_r(str, VENDOR_VALUE_SEPARATOR, &saveptr)) != NULL) {
896     trim(token);
897     strlcpy(bdaddrstr, token, KEY_MAX_LENGTH);
898   } else {
899     return false;
900   }
901 
902   if ((token = strtok_r(NULL, VENDOR_VALUE_SEPARATOR, &saveptr)) != NULL) {
903     trim(token);
904     errno = 0;
905     *lmp_ver = (uint8_t)strtoul(token, &e, 16);
906     if (errno == EINVAL || errno == ERANGE) return false;
907   } else {
908     return false;
909   }
910 
911   if ((token = strtok_r(NULL, VENDOR_VALUE_SEPARATOR, &saveptr)) != NULL) {
912     return token_to_ul(token, lmp_sub_ver);
913   }
914   return false;
915 }
916 
load_to_database(int feature,const char * key,const char * value,interop_entry_type entry_type)917 static bool load_to_database(int feature, const char* key, const char* value,
918                              interop_entry_type entry_type) {
919   if (!strncasecmp(value, ADDR_BASED, strlen(ADDR_BASED))) {
920     RawAddress addr;
921     int len = 0;
922 
923     len = (strlen(key) + 1) / 3;
924     if (len < 3 || len > 4) {
925       log::warn("Ignoring as invalid entry for Address {}", key);
926       return false;
927     }
928 
929     std::string bdstr(key);
930     std::string append_str(":00");
931     for (int i = 6; i > len; i--) bdstr.append(append_str);
932 
933     if (!RawAddress::FromString(bdstr, addr)) {
934       log::warn(
935           "key {} or Bluetooth Address {} is invalid, not added to interop "
936           "list",
937           key, addr);
938       return false;
939     }
940 
941     interop_db_entry_t* entry =
942         (interop_db_entry_t*)osi_calloc(sizeof(interop_db_entry_t));
943     entry->bl_type = INTEROP_BL_TYPE_ADDR;
944     entry->bl_entry_type = entry_type;
945     entry->entry_type.addr_entry.addr = addr;
946     entry->entry_type.addr_entry.feature = (interop_feature_t)feature;
947     entry->entry_type.addr_entry.length = len;
948     interop_database_add_(entry, false);
949 
950   } else if (!strncasecmp(value, NAME_BASED, strlen(NAME_BASED))) {
951     if (strlen(key) > KEY_MAX_LENGTH - 1) {
952       log::warn("ignoring {} due to invalid length", key);
953       return false;
954     }
955     interop_db_entry_t* entry =
956         (interop_db_entry_t*)osi_calloc(sizeof(interop_db_entry_t));
957     entry->bl_type = INTEROP_BL_TYPE_NAME;
958     entry->bl_entry_type = entry_type;
959     strlcpy(entry->entry_type.name_entry.name, key,
960             sizeof(entry->entry_type.name_entry.name));
961     entry->entry_type.name_entry.feature = (interop_feature_t)feature;
962     entry->entry_type.name_entry.length = strlen(key);
963     interop_database_add_(entry, false);
964 
965   } else if (!strncasecmp(value, MNFR_BASED, strlen(MNFR_BASED))) {
966     uint16_t manufacturer;
967 
968     if (strlen(key) != VALID_MNFR_STR_LEN) {
969       log::warn("ignoring {} due to invalid Manufacturer id in config file",
970                 key);
971       return false;
972     }
973 
974     if (token_to_ul((char*)key, &manufacturer) == false) return false;
975 
976     interop_db_entry_t* entry =
977         (interop_db_entry_t*)osi_calloc(sizeof(interop_db_entry_t));
978     entry->bl_type = INTEROP_BL_TYPE_MANUFACTURE;
979     entry->bl_entry_type = entry_type;
980     entry->entry_type.mnfr_entry.feature = (interop_feature_t)feature;
981     entry->entry_type.mnfr_entry.manufacturer = manufacturer;
982     interop_database_add_(entry, false);
983 
984   } else if (!strncasecmp(value, VNDR_PRDT_BASED, strlen(VNDR_PRDT_BASED))) {
985     uint16_t vendor_id;
986     uint16_t product_id = 0;
987     char tmp_key[VALID_VNDR_PRDT_LEN + 1] = {'\0'};
988 
989     if (strlen(key) != VALID_VNDR_PRDT_LEN) {
990       log::warn("ignoring {} due to invalid vendor/product id in config file",
991                 key);
992       return false;
993     }
994 
995     strlcpy(tmp_key, key, VALID_VNDR_PRDT_LEN + 1);
996     if (!get_vendor_product_id(tmp_key, &vendor_id, &product_id)) {
997       log::warn("Error in parsing vendor/product id {}", key);
998       return false;
999     }
1000 
1001     interop_db_entry_t* entry =
1002         (interop_db_entry_t*)osi_calloc(sizeof(interop_db_entry_t));
1003     entry->bl_type = INTEROP_BL_TYPE_VNDR_PRDT;
1004     entry->bl_entry_type = entry_type;
1005     entry->entry_type.vnr_pdt_entry.feature = (interop_feature_t)feature;
1006     entry->entry_type.vnr_pdt_entry.vendor_id = vendor_id;
1007     entry->entry_type.vnr_pdt_entry.product_id = product_id;
1008     interop_database_add_(entry, false);
1009   } else if (!strncasecmp(value, SSR_MAX_LAT_BASED,
1010                           strlen(SSR_MAX_LAT_BASED))) {
1011     uint16_t max_lat;
1012     char tmp_key[KEY_MAX_LENGTH] = {'\0'};
1013     char bdaddr_str[KEY_MAX_LENGTH] = {'\0'};
1014 
1015     if (strlen(key) != VALID_SSR_LAT_LEN) {
1016       log::warn("ignoring {} due to invalid key for ssr max lat in config file",
1017                 key);
1018       return false;
1019     }
1020 
1021     strlcpy(tmp_key, key, KEY_MAX_LENGTH);
1022     if (!get_addr_maxlat(tmp_key, bdaddr_str, &max_lat)) {
1023       log::warn("Error in parsing address and max_lat {}", key);
1024       return false;
1025     }
1026 
1027     int len = 0;
1028 
1029     len = (strlen(bdaddr_str) + 1) / 3;
1030     if (len != 3) {
1031       log::warn("Ignoring as invalid entry for Address {}", bdaddr_str);
1032       return false;
1033     }
1034 
1035     std::string bdstr(bdaddr_str);
1036     std::string append_str(":00:00:00");
1037     RawAddress addr;
1038 
1039     bdstr.append(append_str);
1040 
1041     if (!RawAddress::FromString(bdstr, addr)) {
1042       log::warn(
1043           "key {} or Bluetooth Address {} is invalid, not added to interop "
1044           "list",
1045           key, addr);
1046       return false;
1047     }
1048 
1049     interop_db_entry_t* entry =
1050         (interop_db_entry_t*)osi_calloc(sizeof(interop_db_entry_t));
1051     entry->bl_type = INTEROP_BL_TYPE_SSR_MAX_LAT;
1052     entry->bl_entry_type = entry_type;
1053     entry->entry_type.ssr_max_lat_entry.feature = (interop_feature_t)feature;
1054     entry->entry_type.ssr_max_lat_entry.addr = addr;
1055     entry->entry_type.ssr_max_lat_entry.max_lat = max_lat;
1056     interop_database_add_(entry, false);
1057   } else if (!strncasecmp(value, VERSION_BASED, strlen(VERSION_BASED))) {
1058     uint16_t version;
1059 
1060     if (strlen(key) != VALID_VERSION_LEN) {
1061       log::warn("ignoring {} due to invalid version in config file", key);
1062       return false;
1063     }
1064 
1065     if (token_to_ul((char*)key, &version) == false) return false;
1066 
1067     interop_db_entry_t* entry =
1068         (interop_db_entry_t*)osi_calloc(sizeof(interop_db_entry_t));
1069     entry->bl_type = INTEROP_BL_TYPE_VERSION;
1070     entry->bl_entry_type = entry_type;
1071     entry->entry_type.version_entry.feature = (interop_feature_t)feature;
1072     entry->entry_type.version_entry.version = version;
1073     interop_database_add_(entry, false);
1074   } else if (!strncasecmp(value, LMP_VERSION_BASED,
1075                           strlen(LMP_VERSION_BASED))) {
1076     uint8_t lmp_ver;
1077     uint16_t lmp_sub_ver;
1078     char tmp_key[KEY_MAX_LENGTH] = {'\0'};
1079     char bdaddr_str[KEY_MAX_LENGTH] = {'\0'};
1080 
1081     if (strlen(key) != VALID_LMP_VERSION_LEN) {
1082       log::warn("ignoring {} due to invalid key for lmp ver in config file",
1083                 key);
1084       return false;
1085     }
1086 
1087     strlcpy(tmp_key, key, KEY_MAX_LENGTH);
1088     if (!get_addr_lmp_ver(tmp_key, bdaddr_str, &lmp_ver, &lmp_sub_ver)) {
1089       log::warn("Error in parsing address and lmp_ver {}", key);
1090       return false;
1091     }
1092 
1093     int len = 0;
1094 
1095     len = (strlen(bdaddr_str) + 1) / 3;
1096     if (len != 3) {
1097       log::warn("Ignoring as invalid entry for Address {}", bdaddr_str);
1098       return false;
1099     }
1100 
1101     std::string bdstr(key);
1102     std::string append_str(":00:00:00");
1103     RawAddress addr;
1104 
1105     bdstr.append(append_str);
1106 
1107     if (!RawAddress::FromString(bdstr, addr)) {
1108       log::warn(
1109           "key {} or Bluetooth Address {} is invalid, not added to interop "
1110           "list",
1111           key, addr);
1112       return false;
1113     }
1114 
1115     interop_db_entry_t* entry =
1116         (interop_db_entry_t*)osi_calloc(sizeof(interop_db_entry_t));
1117     entry->bl_type = INTEROP_BL_TYPE_LMP_VERSION;
1118     entry->bl_entry_type = entry_type;
1119     entry->entry_type.lmp_version_entry.feature = (interop_feature_t)feature;
1120     entry->entry_type.lmp_version_entry.addr = addr;
1121     entry->entry_type.lmp_version_entry.lmp_ver = lmp_ver;
1122     entry->entry_type.lmp_version_entry.lmp_sub_ver = lmp_sub_ver;
1123     interop_database_add_(entry, false);
1124   } else if (!strncasecmp(value, ADDR_RANGE_BASED, strlen(ADDR_RANGE_BASED))) {
1125     RawAddress addr_start;
1126     RawAddress addr_end;
1127     char tmp_key[KEY_MAX_LENGTH] = {'\0'};
1128 
1129     if (strlen(key) != VALID_ADDR_RANGE_LEN) {
1130       log::warn("Ignoring as invalid entry for Address range {}", key);
1131       return false;
1132     }
1133 
1134     strlcpy(tmp_key, key, VALID_ADDR_RANGE_LEN + 1);
1135     if (!get_addr_range(tmp_key, &addr_start, &addr_end)) {
1136       log::warn(
1137           "key: {} addr_start {} or addr end  {} is added to interop list", key,
1138           addr_start, addr_end);
1139 
1140       return false;
1141     }
1142 
1143     interop_db_entry_t* entry =
1144         (interop_db_entry_t*)osi_calloc(sizeof(interop_db_entry_t));
1145     entry->bl_type = INTEROP_BL_TYPE_ADDR_RANGE;
1146     entry->bl_entry_type = entry_type;
1147     entry->entry_type.addr_range_entry.addr_start = addr_start;
1148     entry->entry_type.addr_range_entry.addr_end = addr_end;
1149     entry->entry_type.addr_range_entry.feature = (interop_feature_t)feature;
1150     interop_database_add_(entry, false);
1151   }
1152 
1153   log::verbose("feature:: {}, key :: {}, value :: {}", feature, key, value);
1154   return true;
1155 }
1156 
load_config()1157 static void load_config() {
1158   int init_status = interop_config_init();
1159 
1160   if (init_status == -1) {
1161     log::error("Error in initializing interop static config file");
1162     return;
1163   }
1164 
1165   pthread_mutex_lock(&file_lock);
1166   for (const section_t& sec : config_static.get()->sections) {
1167     int feature = -1;
1168     if ((feature = interop_feature_name_to_feature_id(sec.name.c_str())) !=
1169         -1) {
1170       for (const entry_t& entry : sec.entries) {
1171         load_to_database(feature, entry.key.c_str(), entry.value.c_str(),
1172                          INTEROP_ENTRY_TYPE_STATIC);
1173       }
1174     }
1175   }
1176   // We no longer need the static config file
1177   config_static.reset();
1178 
1179   for (const section_t& sec : config_dynamic.get()->sections) {
1180     int feature = -1;
1181     if ((feature = interop_feature_name_to_feature_id(sec.name.c_str())) !=
1182         -1) {
1183       for (const entry_t& entry : sec.entries) {
1184         load_to_database(feature, entry.key.c_str(), entry.value.c_str(),
1185                          INTEROP_ENTRY_TYPE_DYNAMIC);
1186       }
1187     }
1188   }
1189   pthread_mutex_unlock(&file_lock);
1190 }
1191 
interop_config_cleanup(void)1192 static void interop_config_cleanup(void) {
1193   interop_config_flush();
1194 
1195   pthread_mutex_lock(&file_lock);
1196   config_static.reset();
1197   config_dynamic.reset();
1198   pthread_mutex_unlock(&file_lock);
1199   pthread_mutex_destroy(&file_lock);
1200 }
1201 
interop_database_add_addr(const uint16_t feature,const RawAddress * addr,size_t length)1202 void interop_database_add_addr(const uint16_t feature, const RawAddress* addr,
1203                                size_t length) {
1204   log::assert_that(addr != nullptr, "assert failed: addr != nullptr");
1205   log::assert_that(length > 0, "assert failed: length > 0");
1206   log::assert_that(length < sizeof(RawAddress),
1207                    "assert failed: length < sizeof(RawAddress)");
1208 
1209   interop_db_entry_t* entry =
1210       (interop_db_entry_t*)osi_calloc(sizeof(interop_db_entry_t));
1211   entry->bl_type = INTEROP_BL_TYPE_ADDR;
1212   entry->bl_entry_type = INTEROP_ENTRY_TYPE_DYNAMIC;
1213   memcpy(&entry->entry_type.addr_entry.addr, addr, length);
1214   entry->entry_type.addr_entry.feature = (interop_feature_t)feature;
1215   entry->entry_type.addr_entry.length = length;
1216   interop_database_add_(entry, true);
1217 }
1218 
interop_database_add_name(const uint16_t feature,const char * name)1219 void interop_database_add_name(const uint16_t feature, const char* name) {
1220   log::assert_that(name != nullptr, "assert failed: name != nullptr");
1221   const size_t name_length = strlen(name);
1222   log::assert_that(name_length < KEY_MAX_LENGTH,
1223                    "assert failed: name_length < KEY_MAX_LENGTH");
1224 
1225   interop_db_entry_t* entry =
1226       (interop_db_entry_t*)osi_calloc(sizeof(interop_db_entry_t));
1227   entry->bl_type = INTEROP_BL_TYPE_NAME;
1228   entry->bl_entry_type = INTEROP_ENTRY_TYPE_DYNAMIC;
1229   strlcpy(entry->entry_type.name_entry.name, name,
1230           sizeof(entry->entry_type.name_entry.name));
1231   entry->entry_type.name_entry.feature = (interop_feature_t)feature;
1232   entry->entry_type.name_entry.length = name_length;
1233   interop_database_add_(entry, true);
1234 }
1235 
interop_database_add_manufacturer(const interop_feature_t feature,uint16_t manufacturer)1236 void interop_database_add_manufacturer(const interop_feature_t feature,
1237                                        uint16_t manufacturer) {
1238   interop_db_entry_t* entry =
1239       (interop_db_entry_t*)osi_calloc(sizeof(interop_db_entry_t));
1240   entry->bl_type = INTEROP_BL_TYPE_MANUFACTURE;
1241   entry->bl_entry_type = INTEROP_ENTRY_TYPE_DYNAMIC;
1242   entry->entry_type.mnfr_entry.feature = feature;
1243   entry->entry_type.mnfr_entry.manufacturer = manufacturer;
1244   interop_database_add_(entry, true);
1245 }
1246 
interop_database_add_vndr_prdt(const interop_feature_t feature,uint16_t vendor_id,uint16_t product_id)1247 void interop_database_add_vndr_prdt(const interop_feature_t feature,
1248                                     uint16_t vendor_id, uint16_t product_id) {
1249   interop_db_entry_t* entry =
1250       (interop_db_entry_t*)osi_calloc(sizeof(interop_db_entry_t));
1251   entry->bl_type = INTEROP_BL_TYPE_VNDR_PRDT;
1252   entry->bl_entry_type = INTEROP_ENTRY_TYPE_DYNAMIC;
1253   entry->entry_type.vnr_pdt_entry.feature = (interop_feature_t)feature;
1254   entry->entry_type.vnr_pdt_entry.vendor_id = vendor_id;
1255   entry->entry_type.vnr_pdt_entry.product_id = product_id;
1256   interop_database_add_(entry, true);
1257 }
1258 
interop_database_add_addr_max_lat(const interop_feature_t feature,const RawAddress * addr,uint16_t max_lat)1259 void interop_database_add_addr_max_lat(const interop_feature_t feature,
1260                                        const RawAddress* addr,
1261                                        uint16_t max_lat) {
1262   log::assert_that(addr != nullptr, "assert failed: addr != nullptr");
1263 
1264   interop_db_entry_t* entry =
1265       (interop_db_entry_t*)osi_calloc(sizeof(interop_db_entry_t));
1266   entry->bl_type = INTEROP_BL_TYPE_SSR_MAX_LAT;
1267   entry->bl_entry_type = INTEROP_ENTRY_TYPE_DYNAMIC;
1268   entry->entry_type.ssr_max_lat_entry.addr = *addr;
1269   entry->entry_type.ssr_max_lat_entry.feature = feature;
1270   entry->entry_type.ssr_max_lat_entry.max_lat = max_lat;
1271   interop_database_add_(entry, true);
1272 }
1273 
interop_database_add_version(const interop_feature_t feature,uint16_t version)1274 void interop_database_add_version(const interop_feature_t feature,
1275                                   uint16_t version) {
1276   interop_db_entry_t* entry =
1277       (interop_db_entry_t*)osi_calloc(sizeof(interop_db_entry_t));
1278   entry->bl_type = INTEROP_BL_TYPE_VERSION;
1279   entry->bl_entry_type = INTEROP_ENTRY_TYPE_DYNAMIC;
1280   entry->entry_type.version_entry.feature = (interop_feature_t)feature;
1281   entry->entry_type.version_entry.version = version;
1282   interop_database_add_(entry, true);
1283 }
1284 
interop_database_add_addr_lmp_version(const interop_feature_t feature,const RawAddress * addr,uint8_t lmp_ver,uint16_t lmp_sub_ver)1285 void interop_database_add_addr_lmp_version(const interop_feature_t feature,
1286                                            const RawAddress* addr,
1287                                            uint8_t lmp_ver,
1288                                            uint16_t lmp_sub_ver) {
1289   log::assert_that(addr != nullptr, "assert failed: addr != nullptr");
1290 
1291   interop_db_entry_t* entry =
1292       (interop_db_entry_t*)osi_calloc(sizeof(interop_db_entry_t));
1293   entry->bl_type = INTEROP_BL_TYPE_LMP_VERSION;
1294   entry->bl_entry_type = INTEROP_ENTRY_TYPE_DYNAMIC;
1295   entry->entry_type.lmp_version_entry.addr = *addr;
1296   entry->entry_type.lmp_version_entry.feature = feature;
1297   entry->entry_type.lmp_version_entry.lmp_ver = lmp_ver;
1298   entry->entry_type.lmp_version_entry.lmp_sub_ver = lmp_sub_ver;
1299   interop_database_add_(entry, true);
1300 }
1301 
interop_database_match_manufacturer(const interop_feature_t feature,uint16_t manufacturer)1302 bool interop_database_match_manufacturer(const interop_feature_t feature,
1303                                          uint16_t manufacturer) {
1304   interop_db_entry_t entry;
1305 
1306   entry.bl_type = INTEROP_BL_TYPE_MANUFACTURE;
1307   entry.entry_type.mnfr_entry.feature = feature;
1308   entry.entry_type.mnfr_entry.manufacturer = manufacturer;
1309 
1310   if (interop_database_match(
1311           &entry, NULL,
1312           (interop_entry_type)(INTEROP_ENTRY_TYPE_STATIC |
1313                                INTEROP_ENTRY_TYPE_DYNAMIC))) {
1314     log::warn(
1315         "Device with manufacturer id: {} is a match for interop workaround {}",
1316         manufacturer, interop_feature_string_(feature));
1317     return true;
1318   }
1319 
1320   return false;
1321 }
1322 
interop_database_match_name(const interop_feature_t feature,const char * name)1323 bool interop_database_match_name(const interop_feature_t feature,
1324                                  const char* name) {
1325   char trim_name[KEY_MAX_LENGTH] = {'\0'};
1326   log::assert_that(name != nullptr, "assert failed: name != nullptr");
1327 
1328   strlcpy(trim_name, name, KEY_MAX_LENGTH);
1329   interop_db_entry_t entry;
1330 
1331   entry.bl_type = INTEROP_BL_TYPE_NAME;
1332   strlcpy(entry.entry_type.name_entry.name, trim(trim_name), KEY_MAX_LENGTH);
1333   entry.entry_type.name_entry.feature = (interop_feature_t)feature;
1334   entry.entry_type.name_entry.length = strlen(entry.entry_type.name_entry.name);
1335 
1336   if (interop_database_match(
1337           &entry, NULL,
1338           (interop_entry_type)(INTEROP_ENTRY_TYPE_STATIC |
1339                                INTEROP_ENTRY_TYPE_DYNAMIC))) {
1340     log::warn("Device with name: {} is a match for interop workaround {}", name,
1341               interop_feature_string_(feature));
1342     return true;
1343   }
1344 
1345   return false;
1346 }
1347 
interop_database_match_addr(const interop_feature_t feature,const RawAddress * addr)1348 bool interop_database_match_addr(const interop_feature_t feature,
1349                                  const RawAddress* addr) {
1350   log::assert_that(addr != nullptr, "assert failed: addr != nullptr");
1351 
1352   interop_db_entry_t entry;
1353 
1354   entry.bl_type = INTEROP_BL_TYPE_ADDR;
1355   entry.entry_type.addr_entry.addr = *addr;
1356   entry.entry_type.addr_entry.feature = (interop_feature_t)feature;
1357   entry.entry_type.addr_entry.length = sizeof(RawAddress);
1358 
1359   if (interop_database_match(
1360           &entry, NULL,
1361           (interop_entry_type)(INTEROP_ENTRY_TYPE_STATIC |
1362                                INTEROP_ENTRY_TYPE_DYNAMIC))) {
1363     log::warn("Device {} is a match for interop workaround {}.", *addr,
1364               interop_feature_string_(feature));
1365     return true;
1366   }
1367 
1368   entry.bl_type = INTEROP_BL_TYPE_ADDR_RANGE;
1369   entry.bl_entry_type = INTEROP_ENTRY_TYPE_STATIC;
1370   entry.entry_type.addr_range_entry.addr_start = *addr;
1371   entry.entry_type.addr_range_entry.feature = (interop_feature_t)feature;
1372 
1373   if (interop_database_match(&entry, NULL,
1374                              (interop_entry_type)(INTEROP_ENTRY_TYPE_STATIC))) {
1375     log::warn("Device {} is a match for interop workaround {}.", *addr,
1376               interop_feature_string_(feature));
1377     return true;
1378   }
1379 
1380   return false;
1381 }
1382 
interop_database_match_vndr_prdt(const interop_feature_t feature,uint16_t vendor_id,uint16_t product_id)1383 bool interop_database_match_vndr_prdt(const interop_feature_t feature,
1384                                       uint16_t vendor_id, uint16_t product_id) {
1385   interop_db_entry_t entry;
1386 
1387   entry.bl_type = INTEROP_BL_TYPE_VNDR_PRDT;
1388 
1389   entry.entry_type.vnr_pdt_entry.feature = (interop_feature_t)feature;
1390   entry.entry_type.vnr_pdt_entry.vendor_id = vendor_id;
1391   entry.entry_type.vnr_pdt_entry.product_id = product_id;
1392   if (interop_database_match(
1393           &entry, NULL,
1394           (interop_entry_type)(INTEROP_ENTRY_TYPE_STATIC |
1395                                INTEROP_ENTRY_TYPE_DYNAMIC))) {
1396     log::warn(
1397         "Device with vendor_id: {} product_id: {} is a match for interop "
1398         "workaround {}",
1399         vendor_id, product_id, interop_feature_string_(feature));
1400     return true;
1401   }
1402 
1403   return false;
1404 }
1405 
interop_database_match_addr_get_max_lat(const interop_feature_t feature,const RawAddress * addr,uint16_t * max_lat)1406 bool interop_database_match_addr_get_max_lat(const interop_feature_t feature,
1407                                              const RawAddress* addr,
1408                                              uint16_t* max_lat) {
1409   interop_db_entry_t entry;
1410   interop_db_entry_t* ret_entry = NULL;
1411 
1412   entry.bl_type = INTEROP_BL_TYPE_SSR_MAX_LAT;
1413 
1414   entry.entry_type.ssr_max_lat_entry.feature = feature;
1415   entry.entry_type.ssr_max_lat_entry.addr = *addr;
1416   entry.entry_type.ssr_max_lat_entry.feature = feature;
1417   if (interop_database_match(
1418           &entry, &ret_entry,
1419           (interop_entry_type)(INTEROP_ENTRY_TYPE_STATIC |
1420                                INTEROP_ENTRY_TYPE_DYNAMIC))) {
1421     log::warn("Device {} is a match for interop workaround {}.", *addr,
1422               interop_feature_string_(feature));
1423     *max_lat = ret_entry->entry_type.ssr_max_lat_entry.max_lat;
1424     return true;
1425   }
1426 
1427   return false;
1428 }
1429 
interop_database_match_version(const interop_feature_t feature,uint16_t version)1430 bool interop_database_match_version(const interop_feature_t feature,
1431                                     uint16_t version) {
1432   interop_db_entry_t entry;
1433 
1434   entry.bl_type = INTEROP_BL_TYPE_VERSION;
1435 
1436   entry.entry_type.version_entry.feature = (interop_feature_t)feature;
1437   entry.entry_type.version_entry.version = version;
1438   if (interop_database_match(
1439           &entry, NULL,
1440           (interop_entry_type)(INTEROP_ENTRY_TYPE_STATIC |
1441                                INTEROP_ENTRY_TYPE_DYNAMIC))) {
1442     log::warn(
1443         "Device with version: 0x{:04x} is a match for interop workaround {}",
1444         version, interop_feature_string_(feature));
1445     return true;
1446   }
1447 
1448   return false;
1449 }
1450 
interop_database_match_addr_get_lmp_ver(const interop_feature_t feature,const RawAddress * addr,uint8_t * lmp_ver,uint16_t * lmp_sub_ver)1451 bool interop_database_match_addr_get_lmp_ver(const interop_feature_t feature,
1452                                              const RawAddress* addr,
1453                                              uint8_t* lmp_ver,
1454                                              uint16_t* lmp_sub_ver) {
1455   interop_db_entry_t entry;
1456   interop_db_entry_t* ret_entry = NULL;
1457 
1458   entry.bl_type = INTEROP_BL_TYPE_LMP_VERSION;
1459 
1460   entry.entry_type.lmp_version_entry.feature = feature;
1461   entry.entry_type.lmp_version_entry.addr = *addr;
1462   entry.entry_type.lmp_version_entry.feature = feature;
1463   if (interop_database_match(
1464           &entry, &ret_entry,
1465           (interop_entry_type)(INTEROP_ENTRY_TYPE_STATIC |
1466                                INTEROP_ENTRY_TYPE_DYNAMIC))) {
1467     log::warn("Device {} is a match for interop workaround {}.", *addr,
1468               interop_feature_string_(feature));
1469     *lmp_ver = ret_entry->entry_type.lmp_version_entry.lmp_ver;
1470     *lmp_sub_ver = ret_entry->entry_type.lmp_version_entry.lmp_sub_ver;
1471     return true;
1472   }
1473 
1474   return false;
1475 }
1476 
interop_database_remove_name(const interop_feature_t feature,const char * name)1477 bool interop_database_remove_name(const interop_feature_t feature,
1478                                   const char* name) {
1479   log::assert_that(name != nullptr, "assert failed: name != nullptr");
1480 
1481   interop_db_entry_t entry;
1482 
1483   entry.bl_type = INTEROP_BL_TYPE_NAME;
1484   entry.bl_entry_type = INTEROP_ENTRY_TYPE_DYNAMIC;
1485   strlcpy(entry.entry_type.name_entry.name, name, 20);
1486   entry.entry_type.name_entry.feature = (interop_feature_t)feature;
1487   entry.entry_type.name_entry.length = strlen(entry.entry_type.name_entry.name);
1488   if (interop_database_remove_(&entry)) {
1489     log::warn("Device with name: {} is removed from interop workaround {}",
1490               name, interop_feature_string_(feature));
1491     return true;
1492   }
1493 
1494   return false;
1495 }
1496 
interop_database_remove_manufacturer(const interop_feature_t feature,uint16_t manufacturer)1497 bool interop_database_remove_manufacturer(const interop_feature_t feature,
1498                                           uint16_t manufacturer) {
1499   interop_db_entry_t entry;
1500 
1501   entry.bl_type = INTEROP_BL_TYPE_MANUFACTURE;
1502   entry.bl_entry_type = INTEROP_ENTRY_TYPE_DYNAMIC;
1503   entry.entry_type.mnfr_entry.feature = feature;
1504   entry.entry_type.mnfr_entry.manufacturer = manufacturer;
1505   if (interop_database_remove_(&entry)) {
1506     log::warn(
1507         "Device with manufacturer id: {} is removed from interop workaround {}",
1508         manufacturer, interop_feature_string_(feature));
1509     return true;
1510   }
1511 
1512   return false;
1513 }
1514 
interop_database_remove_addr(const interop_feature_t feature,const RawAddress * addr)1515 bool interop_database_remove_addr(const interop_feature_t feature,
1516                                   const RawAddress* addr) {
1517   log::assert_that(addr != nullptr, "assert failed: addr != nullptr");
1518 
1519   interop_db_entry_t entry;
1520 
1521   entry.bl_type = INTEROP_BL_TYPE_ADDR;
1522   entry.bl_entry_type = INTEROP_ENTRY_TYPE_DYNAMIC;
1523   entry.entry_type.addr_entry.addr = *addr;
1524   entry.entry_type.addr_entry.feature = (interop_feature_t)feature;
1525   entry.entry_type.addr_entry.length = sizeof(RawAddress);
1526   if (interop_database_remove_(&entry)) {
1527     log::warn("Device {} is a removed from interop workaround {}.", *addr,
1528               interop_feature_string_(feature));
1529     return true;
1530   }
1531 
1532   return false;
1533 }
1534 
interop_database_remove_feature(const interop_feature_t feature)1535 bool interop_database_remove_feature(const interop_feature_t feature) {
1536   if (interop_list == NULL || list_length(interop_list) == 0) return false;
1537 
1538   list_node_t* node = list_begin(interop_list);
1539   while (node != list_end(interop_list)) {
1540     interop_db_entry_t* entry =
1541         static_cast<interop_db_entry_t*>(list_node(node));
1542     log::assert_that(entry != nullptr, "assert failed: entry != nullptr");
1543 
1544     bool entry_match = false;
1545     if (entry->bl_entry_type == INTEROP_ENTRY_TYPE_DYNAMIC) {
1546       switch (entry->bl_type) {
1547         case INTEROP_BL_TYPE_ADDR:
1548           if (entry->entry_type.addr_entry.feature == feature) {
1549             entry_match = true;
1550           }
1551           break;
1552         case INTEROP_BL_TYPE_NAME:
1553           if (entry->entry_type.name_entry.feature == feature) {
1554             entry_match = true;
1555           }
1556           break;
1557         case INTEROP_BL_TYPE_MANUFACTURE:
1558           if (entry->entry_type.mnfr_entry.feature == feature) {
1559             entry_match = true;
1560           }
1561           break;
1562         case INTEROP_BL_TYPE_VNDR_PRDT:
1563           if (entry->entry_type.vnr_pdt_entry.feature == feature) {
1564             entry_match = true;
1565           }
1566           break;
1567         case INTEROP_BL_TYPE_SSR_MAX_LAT:
1568           if (entry->entry_type.ssr_max_lat_entry.feature == feature) {
1569             entry_match = true;
1570           }
1571           break;
1572         case INTEROP_BL_TYPE_VERSION:
1573           if (entry->entry_type.version_entry.feature == feature) {
1574             entry_match = true;
1575           }
1576           break;
1577         case INTEROP_BL_TYPE_LMP_VERSION:
1578           if (entry->entry_type.lmp_version_entry.feature == feature) {
1579             entry_match = true;
1580           }
1581           break;
1582         default:
1583           break;
1584       }
1585     }
1586 
1587     node = list_next(node);
1588 
1589     if (entry_match) {
1590       pthread_mutex_lock(&interop_list_lock);
1591       list_remove(interop_list, (void*)entry);
1592       pthread_mutex_unlock(&interop_list_lock);
1593     }
1594   }
1595 
1596   for (const section_t& sec : config_dynamic.get()->sections) {
1597     if (feature == interop_feature_name_to_feature_id(sec.name.c_str())) {
1598       log::warn("found feature - {}", interop_feature_string_(feature));
1599       interop_config_remove_section(sec.name);
1600       return true;
1601     }
1602   }
1603 
1604   return false;
1605 }
1606 
interop_database_remove_vndr_prdt(const interop_feature_t feature,uint16_t vendor_id,uint16_t product_id)1607 bool interop_database_remove_vndr_prdt(const interop_feature_t feature,
1608                                        uint16_t vendor_id,
1609                                        uint16_t product_id) {
1610   interop_db_entry_t entry;
1611 
1612   entry.bl_type = INTEROP_BL_TYPE_VNDR_PRDT;
1613   entry.bl_entry_type = INTEROP_ENTRY_TYPE_DYNAMIC;
1614 
1615   entry.entry_type.vnr_pdt_entry.feature = (interop_feature_t)feature;
1616   entry.entry_type.vnr_pdt_entry.vendor_id = vendor_id;
1617   entry.entry_type.vnr_pdt_entry.product_id = product_id;
1618 
1619   if (interop_database_remove_(&entry)) {
1620     log::warn(
1621         "Device with vendor_id: {} product_id: {} is removed from interop "
1622         "workaround {}",
1623         vendor_id, product_id, interop_feature_string_(feature));
1624     return true;
1625   }
1626   return false;
1627 }
1628 
interop_database_remove_addr_max_lat(const interop_feature_t feature,const RawAddress * addr,uint16_t max_lat)1629 bool interop_database_remove_addr_max_lat(const interop_feature_t feature,
1630                                           const RawAddress* addr,
1631                                           uint16_t max_lat) {
1632   interop_db_entry_t entry;
1633 
1634   entry.bl_type = INTEROP_BL_TYPE_SSR_MAX_LAT;
1635   entry.bl_entry_type = INTEROP_ENTRY_TYPE_DYNAMIC;
1636 
1637   entry.entry_type.ssr_max_lat_entry.addr = *addr;
1638   entry.entry_type.ssr_max_lat_entry.feature = feature;
1639   entry.entry_type.ssr_max_lat_entry.max_lat = max_lat;
1640 
1641   if (interop_database_remove_(&entry)) {
1642     log::warn("Device {} is a removed from interop workaround {}.", *addr,
1643               interop_feature_string_(feature));
1644     return true;
1645   }
1646   return false;
1647 }
1648 
interop_database_remove_version(const interop_feature_t feature,uint16_t version)1649 bool interop_database_remove_version(const interop_feature_t feature,
1650                                      uint16_t version) {
1651   interop_db_entry_t entry;
1652 
1653   entry.bl_type = INTEROP_BL_TYPE_VERSION;
1654   entry.bl_entry_type = INTEROP_ENTRY_TYPE_DYNAMIC;
1655 
1656   entry.entry_type.version_entry.feature = (interop_feature_t)feature;
1657   entry.entry_type.version_entry.version = version;
1658 
1659   if (interop_database_remove_(&entry)) {
1660     log::warn(
1661         "Device with version: 0x{:04x} is removed from interop workaround {}",
1662         version, interop_feature_string_(feature));
1663     return true;
1664   }
1665   return false;
1666 }
1667 
interop_database_remove_addr_lmp_version(const interop_feature_t feature,const RawAddress * addr,uint8_t lmp_ver,uint16_t lmp_sub_ver)1668 bool interop_database_remove_addr_lmp_version(const interop_feature_t feature,
1669                                               const RawAddress* addr,
1670                                               uint8_t lmp_ver,
1671                                               uint16_t lmp_sub_ver) {
1672   interop_db_entry_t entry;
1673 
1674   entry.bl_type = INTEROP_BL_TYPE_LMP_VERSION;
1675   entry.bl_entry_type = INTEROP_ENTRY_TYPE_DYNAMIC;
1676 
1677   entry.entry_type.lmp_version_entry.addr = *addr;
1678   entry.entry_type.lmp_version_entry.feature = feature;
1679   entry.entry_type.lmp_version_entry.lmp_ver = lmp_ver;
1680   entry.entry_type.lmp_version_entry.lmp_sub_ver = lmp_sub_ver;
1681 
1682   if (interop_database_remove_(&entry)) {
1683     log::warn("Device {} is a removed from interop workaround {}.", *addr,
1684               interop_feature_string_(feature));
1685     return true;
1686   }
1687   return false;
1688 }
1689