• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /******************************************************************************
2  *
3  *  Copyright 2015 Google, Inc.
4  *
5  *  Licensed under the Apache License, Version 2.0 (the "License");
6  *  you may not use this file except in compliance with the License.
7  *  You may obtain a copy of the License at:
8  *
9  *  http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *  Unless required by applicable law or agreed to in writing, software
12  *  distributed under the License is distributed on an "AS IS" BASIS,
13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *  See the License for the specific language governing permissions and
15  *  limitations under the License.
16  *
17  ******************************************************************************/
18 
19 #define LOG_TAG "bt_device_interop"
20 
21 #include "device/include/interop.h"
22 
23 #include <base/logging.h>
24 #include <string.h>  // For memcmp
25 
26 #include "btcore/include/module.h"
27 #include "check.h"
28 #include "device/include/interop_database.h"
29 #include "osi/include/allocator.h"
30 #include "osi/include/list.h"
31 #include "osi/include/log.h"
32 #include "types/raw_address.h"
33 
34 #define CASE_RETURN_STR(const) \
35   case const:                  \
36     return #const;
37 
38 static list_t* interop_list = NULL;
39 
40 static const char* interop_feature_string_(const interop_feature_t feature);
41 static void interop_free_entry_(void* data);
42 static void interop_lazy_init_(void);
43 static bool interop_match_fixed_(const interop_feature_t feature,
44                                  const RawAddress* addr);
45 static bool interop_match_dynamic_(const interop_feature_t feature,
46                                    const RawAddress* addr);
47 static bool interop_match_range_(const interop_feature_t feature,
48                                  const RawAddress* addr);
49 
50 // Interface functions
51 
interop_match_addr(const interop_feature_t feature,const RawAddress * addr)52 bool interop_match_addr(const interop_feature_t feature,
53                         const RawAddress* addr) {
54   CHECK(addr);
55 
56   if (interop_match_fixed_(feature, addr) ||
57       interop_match_dynamic_(feature, addr) ||
58       interop_match_range_(feature, addr)) {
59     LOG_INFO("%s() Device %s is a match for interop workaround %s.", __func__,
60              addr->ToString().c_str(), interop_feature_string_(feature));
61     return true;
62   }
63 
64   return false;
65 }
66 
interop_match_name(const interop_feature_t feature,const char * name)67 bool interop_match_name(const interop_feature_t feature, const char* name) {
68   CHECK(name);
69 
70   const size_t db_size =
71       sizeof(interop_name_database) / sizeof(interop_name_entry_t);
72   for (size_t i = 0; i != db_size; ++i) {
73     if (feature == interop_name_database[i].feature &&
74         strlen(name) >= interop_name_database[i].length &&
75         strncmp(name, interop_name_database[i].name,
76                 interop_name_database[i].length) == 0) {
77       LOG_INFO("%s() Device %s is a match for interop workaround %s.", __func__,
78                name, interop_feature_string_(feature));
79       return true;
80     }
81   }
82 
83   return false;
84 }
85 
interop_database_add(uint16_t feature,const RawAddress * addr,size_t length)86 void interop_database_add(uint16_t feature, const RawAddress* addr,
87                           size_t length) {
88   CHECK(addr);
89   CHECK(length > 0);
90   CHECK(length < RawAddress::kLength);
91 
92   interop_addr_entry_t* entry = static_cast<interop_addr_entry_t*>(
93       osi_calloc(sizeof(interop_addr_entry_t)));
94   memcpy(&entry->addr, addr, length);
95   entry->feature = static_cast<interop_feature_t>(feature);
96   entry->length = length;
97 
98   interop_lazy_init_();
99   list_append(interop_list, entry);
100 }
101 
interop_database_clear()102 void interop_database_clear() {
103   if (interop_list) list_clear(interop_list);
104 }
105 
106 // Module life-cycle functions
107 
interop_clean_up(void)108 static future_t* interop_clean_up(void) {
109   list_free(interop_list);
110   interop_list = NULL;
111   return future_new_immediate(FUTURE_SUCCESS);
112 }
113 
114 EXPORT_SYMBOL module_t interop_module = {
115     .name = INTEROP_MODULE,
116     .init = NULL,
117     .start_up = NULL,
118     .shut_down = NULL,
119     .clean_up = interop_clean_up,
120     .dependencies = {NULL},
121 };
122 
123 // Local functions
124 
interop_feature_string_(const interop_feature_t feature)125 static const char* interop_feature_string_(const interop_feature_t feature) {
126   switch (feature) {
127     CASE_RETURN_STR(INTEROP_DISABLE_LE_SECURE_CONNECTIONS)
128     CASE_RETURN_STR(INTEROP_AUTO_RETRY_PAIRING)
129     CASE_RETURN_STR(INTEROP_DISABLE_ABSOLUTE_VOLUME)
130     CASE_RETURN_STR(INTEROP_DISABLE_AUTO_PAIRING)
131     CASE_RETURN_STR(INTEROP_KEYBOARD_REQUIRES_FIXED_PIN)
132     CASE_RETURN_STR(INTEROP_2MBPS_LINK_ONLY)
133     CASE_RETURN_STR(INTEROP_HID_PREF_CONN_SUP_TIMEOUT_3S)
134     CASE_RETURN_STR(INTEROP_GATTC_NO_SERVICE_CHANGED_IND)
135     CASE_RETURN_STR(INTEROP_DISABLE_AVDTP_RECONFIGURE)
136     CASE_RETURN_STR(INTEROP_DYNAMIC_ROLE_SWITCH)
137     CASE_RETURN_STR(INTEROP_DISABLE_ROLE_SWITCH)
138     CASE_RETURN_STR(INTEROP_HID_HOST_LIMIT_SNIFF_INTERVAL)
139     CASE_RETURN_STR(INTEROP_DISABLE_NAME_REQUEST)
140     CASE_RETURN_STR(INTEROP_AVRCP_1_4_ONLY)
141     CASE_RETURN_STR(INTEROP_DISABLE_SNIFF)
142     CASE_RETURN_STR(INTEROP_DISABLE_AVDTP_SUSPEND)
143     CASE_RETURN_STR(INTEROP_SLC_SKIP_BIND_COMMAND)
144     CASE_RETURN_STR(INTEROP_AVRCP_1_3_ONLY)
145     CASE_RETURN_STR(INTEROP_DISABLE_ROBUST_CACHING);
146   }
147 
148   return "UNKNOWN";
149 }
150 
interop_free_entry_(void * data)151 static void interop_free_entry_(void* data) {
152   interop_addr_entry_t* entry = (interop_addr_entry_t*)data;
153   osi_free(entry);
154 }
155 
interop_lazy_init_(void)156 static void interop_lazy_init_(void) {
157   if (interop_list == NULL) {
158     interop_list = list_new(interop_free_entry_);
159   }
160 }
161 
interop_match_dynamic_(const interop_feature_t feature,const RawAddress * addr)162 static bool interop_match_dynamic_(const interop_feature_t feature,
163                                    const RawAddress* addr) {
164   if (interop_list == NULL || list_length(interop_list) == 0) return false;
165 
166   const list_node_t* node = list_begin(interop_list);
167   while (node != list_end(interop_list)) {
168     interop_addr_entry_t* entry =
169         static_cast<interop_addr_entry_t*>(list_node(node));
170     CHECK(entry);
171 
172     if (feature == entry->feature &&
173         memcmp(addr, &entry->addr, entry->length) == 0)
174       return true;
175 
176     node = list_next(node);
177   }
178   return false;
179 }
180 
interop_match_fixed_(const interop_feature_t feature,const RawAddress * addr)181 static bool interop_match_fixed_(const interop_feature_t feature,
182                                  const RawAddress* addr) {
183   CHECK(addr);
184 
185   const size_t db_size =
186       sizeof(interop_addr_database) / sizeof(interop_addr_entry_t);
187   for (size_t i = 0; i != db_size; ++i) {
188     if (feature == interop_addr_database[i].feature &&
189         memcmp(addr, &interop_addr_database[i].addr,
190                interop_addr_database[i].length) == 0) {
191       return true;
192     }
193   }
194 
195   return false;
196 }
197 
interop_match_range_(const interop_feature_t feature,const RawAddress * addr)198 static bool interop_match_range_(const interop_feature_t feature,
199                                  const RawAddress* addr) {
200   CHECK(addr);
201 
202   const size_t db_size =
203       sizeof(interop_addr_range_database) / sizeof(interop_addr_range_entry_t);
204   for (size_t i = 0; i != db_size; ++i) {
205     if (feature == interop_addr_range_database[i].feature &&
206         *addr >= interop_addr_range_database[i].addr_start &&
207         *addr <= interop_addr_range_database[i].addr_end) {
208       return true;
209     }
210   }
211 
212   return false;
213 }
214