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