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