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