blob: e4bce56fe1bf275b32d2cc32d9b929ce1cd2be11 [file] [log] [blame]
Andre Eisenbach7927f682015-07-02 16:14:28 -07001/******************************************************************************
2 *
Jakub Pawlowski5b790fe2017-09-18 09:00:20 -07003 * Copyright 2015 Google, Inc.
Andre Eisenbach7927f682015-07-02 16:14:28 -07004 *
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
Jack Hef2af1c42016-12-13 01:59:12 -080021#include <base/logging.h>
Myles Watson4451b3b2016-11-09 10:20:44 -080022#include <string.h> // For memcmp
Andre Eisenbach7927f682015-07-02 16:14:28 -070023
Andre Eisenbache42d1d72016-01-14 02:00:24 -080024#include "btcore/include/module.h"
Andre Eisenbach7927f682015-07-02 16:14:28 -070025#include "device/include/interop.h"
26#include "device/include/interop_database.h"
Andre Eisenbache42d1d72016-01-14 02:00:24 -080027#include "osi/include/allocator.h"
28#include "osi/include/list.h"
Andre Eisenbach7927f682015-07-02 16:14:28 -070029#include "osi/include/log.h"
30
Myles Watson4451b3b2016-11-09 10:20:44 -080031#define CASE_RETURN_STR(const) \
32 case const: \
33 return #const;
Andre Eisenbach7927f682015-07-02 16:14:28 -070034
Myles Watson4451b3b2016-11-09 10:20:44 -080035static list_t* interop_list = NULL;
Andre Eisenbache42d1d72016-01-14 02:00:24 -080036
37static const char* interop_feature_string_(const interop_feature_t feature);
Myles Watson4451b3b2016-11-09 10:20:44 -080038static void interop_free_entry_(void* data);
Andre Eisenbache42d1d72016-01-14 02:00:24 -080039static void interop_lazy_init_(void);
Myles Watson4451b3b2016-11-09 10:20:44 -080040static bool interop_match_fixed_(const interop_feature_t feature,
Jakub Pawlowskia484a882017-06-24 17:30:18 -070041 const RawAddress* addr);
Myles Watson4451b3b2016-11-09 10:20:44 -080042static bool interop_match_dynamic_(const interop_feature_t feature,
Jakub Pawlowskia484a882017-06-24 17:30:18 -070043 const RawAddress* addr);
Andre Eisenbache42d1d72016-01-14 02:00:24 -080044
45// Interface functions
46
Myles Watson4451b3b2016-11-09 10:20:44 -080047bool interop_match_addr(const interop_feature_t feature,
Jakub Pawlowskia484a882017-06-24 17:30:18 -070048 const RawAddress* addr) {
Jack Hef2af1c42016-12-13 01:59:12 -080049 CHECK(addr);
Andre Eisenbache42d1d72016-01-14 02:00:24 -080050
Myles Watson4451b3b2016-11-09 10:20:44 -080051 if (interop_match_fixed_(feature, addr) ||
52 interop_match_dynamic_(feature, addr)) {
Andre Eisenbache42d1d72016-01-14 02:00:24 -080053 LOG_WARN(LOG_TAG, "%s() Device %s is a match for interop workaround %s.",
Jakub Pawlowskib707f442017-07-03 15:39:36 -070054 __func__, addr->ToString().c_str(),
Myles Watson4451b3b2016-11-09 10:20:44 -080055 interop_feature_string_(feature));
Andre Eisenbache42d1d72016-01-14 02:00:24 -080056 return true;
57 }
58
59 return false;
60}
61
Myles Watson4451b3b2016-11-09 10:20:44 -080062bool interop_match_name(const interop_feature_t feature, const char* name) {
Jack Hef2af1c42016-12-13 01:59:12 -080063 CHECK(name);
Andre Eisenbach7ee02bd2016-04-11 14:50:41 -070064
Myles Watson4451b3b2016-11-09 10:20:44 -080065 const size_t db_size =
66 sizeof(interop_name_database) / sizeof(interop_name_entry_t);
Andre Eisenbach7ee02bd2016-04-11 14:50:41 -070067 for (size_t i = 0; i != db_size; ++i) {
68 if (feature == interop_name_database[i].feature &&
69 strlen(name) >= interop_name_database[i].length &&
Myles Watson4451b3b2016-11-09 10:20:44 -080070 strncmp(name, interop_name_database[i].name,
71 interop_name_database[i].length) == 0) {
Andre Eisenbach7ee02bd2016-04-11 14:50:41 -070072 return true;
73 }
74 }
75
76 return false;
77}
78
Jack He9af00782018-01-31 16:51:26 -080079void interop_database_add(uint16_t feature, const RawAddress* addr,
Myles Watson4451b3b2016-11-09 10:20:44 -080080 size_t length) {
Jack Hef2af1c42016-12-13 01:59:12 -080081 CHECK(addr);
82 CHECK(length > 0);
Jakub Pawlowski2e05f0d2017-08-16 06:41:02 -070083 CHECK(length < RawAddress::kLength);
Andre Eisenbache42d1d72016-01-14 02:00:24 -080084
Myles Watson4451b3b2016-11-09 10:20:44 -080085 interop_addr_entry_t* entry = static_cast<interop_addr_entry_t*>(
86 osi_calloc(sizeof(interop_addr_entry_t)));
Andre Eisenbache42d1d72016-01-14 02:00:24 -080087 memcpy(&entry->addr, addr, length);
Pavlin Radoslavovb2a292b2016-10-14 19:34:48 -070088 entry->feature = static_cast<interop_feature_t>(feature);
Andre Eisenbache42d1d72016-01-14 02:00:24 -080089 entry->length = length;
90
91 interop_lazy_init_();
92 list_append(interop_list, entry);
93}
94
95void interop_database_clear() {
Myles Watson4451b3b2016-11-09 10:20:44 -080096 if (interop_list) list_clear(interop_list);
Andre Eisenbache42d1d72016-01-14 02:00:24 -080097}
98
99// Module life-cycle functions
100
Myles Watson4451b3b2016-11-09 10:20:44 -0800101static future_t* interop_clean_up(void) {
Andre Eisenbache42d1d72016-01-14 02:00:24 -0800102 list_free(interop_list);
103 interop_list = NULL;
104 return future_new_immediate(FUTURE_SUCCESS);
105}
106
107EXPORT_SYMBOL module_t interop_module = {
Myles Watson4451b3b2016-11-09 10:20:44 -0800108 .name = INTEROP_MODULE,
109 .init = NULL,
110 .start_up = NULL,
111 .shut_down = NULL,
112 .clean_up = interop_clean_up,
113 .dependencies = {NULL},
Andre Eisenbache42d1d72016-01-14 02:00:24 -0800114};
115
116// Local functions
117
118static const char* interop_feature_string_(const interop_feature_t feature) {
Andre Eisenbach7927f682015-07-02 16:14:28 -0700119 switch (feature) {
120 CASE_RETURN_STR(INTEROP_DISABLE_LE_SECURE_CONNECTIONS)
Andre Eisenbach27c4e632015-07-06 15:43:15 -0700121 CASE_RETURN_STR(INTEROP_AUTO_RETRY_PAIRING)
Andre Eisenbachd0aa6cc2015-12-11 12:32:21 -0800122 CASE_RETURN_STR(INTEROP_DISABLE_ABSOLUTE_VOLUME)
Andre Eisenbach7ee02bd2016-04-11 14:50:41 -0700123 CASE_RETURN_STR(INTEROP_DISABLE_AUTO_PAIRING)
124 CASE_RETURN_STR(INTEROP_KEYBOARD_REQUIRES_FIXED_PIN)
Sathya Kumarf527ce22016-01-07 17:26:05 -0600125 CASE_RETURN_STR(INTEROP_2MBPS_LINK_ONLY)
Jakub Pawlowski9e674752017-03-28 12:58:34 -0700126 CASE_RETURN_STR(INTEROP_HID_PREF_CONN_SUP_TIMEOUT_3S)
Myles Watson43c7f9f2017-05-25 17:24:49 -0700127 CASE_RETURN_STR(INTEROP_GATTC_NO_SERVICE_CHANGED_IND)
Pavlin Radoslavove91297a2017-06-19 12:44:11 -0700128 CASE_RETURN_STR(INTEROP_DISABLE_AVDTP_RECONFIGURE)
Srinu Jella942648e2016-12-08 19:03:20 +0530129 CASE_RETURN_STR(INTEROP_DYNAMIC_ROLE_SWITCH)
Srinu Jella811200c2016-12-07 19:16:31 +0530130 CASE_RETURN_STR(INTEROP_DISABLE_ROLE_SWITCH)
Andre Eisenbach85d56a82019-06-13 11:50:57 -0700131 CASE_RETURN_STR(INTEROP_HID_HOST_LIMIT_SNIFF_INTERVAL)
Andre Eisenbach7927f682015-07-02 16:14:28 -0700132 }
133
134 return "UNKNOWN";
135}
136
Myles Watson4451b3b2016-11-09 10:20:44 -0800137static void interop_free_entry_(void* data) {
138 interop_addr_entry_t* entry = (interop_addr_entry_t*)data;
Andre Eisenbache42d1d72016-01-14 02:00:24 -0800139 osi_free(entry);
140}
Andre Eisenbach7927f682015-07-02 16:14:28 -0700141
Andre Eisenbache42d1d72016-01-14 02:00:24 -0800142static void interop_lazy_init_(void) {
143 if (interop_list == NULL) {
144 interop_list = list_new(interop_free_entry_);
145 }
146}
147
Myles Watson4451b3b2016-11-09 10:20:44 -0800148static bool interop_match_dynamic_(const interop_feature_t feature,
Jakub Pawlowskia484a882017-06-24 17:30:18 -0700149 const RawAddress* addr) {
Myles Watson4451b3b2016-11-09 10:20:44 -0800150 if (interop_list == NULL || list_length(interop_list) == 0) return false;
Andre Eisenbache42d1d72016-01-14 02:00:24 -0800151
Myles Watson4451b3b2016-11-09 10:20:44 -0800152 const list_node_t* node = list_begin(interop_list);
Andre Eisenbache42d1d72016-01-14 02:00:24 -0800153 while (node != list_end(interop_list)) {
Myles Watson4451b3b2016-11-09 10:20:44 -0800154 interop_addr_entry_t* entry =
155 static_cast<interop_addr_entry_t*>(list_node(node));
Jack Hef2af1c42016-12-13 01:59:12 -0800156 CHECK(entry);
Andre Eisenbache42d1d72016-01-14 02:00:24 -0800157
Myles Watson4451b3b2016-11-09 10:20:44 -0800158 if (feature == entry->feature &&
159 memcmp(addr, &entry->addr, entry->length) == 0)
Andre Eisenbache42d1d72016-01-14 02:00:24 -0800160 return true;
161
162 node = list_next(node);
163 }
164 return false;
165}
166
Myles Watson4451b3b2016-11-09 10:20:44 -0800167static bool interop_match_fixed_(const interop_feature_t feature,
Jakub Pawlowskia484a882017-06-24 17:30:18 -0700168 const RawAddress* addr) {
Jack Hef2af1c42016-12-13 01:59:12 -0800169 CHECK(addr);
Andre Eisenbach7927f682015-07-02 16:14:28 -0700170
Myles Watson4451b3b2016-11-09 10:20:44 -0800171 const size_t db_size =
172 sizeof(interop_addr_database) / sizeof(interop_addr_entry_t);
Andre Eisenbach7927f682015-07-02 16:14:28 -0700173 for (size_t i = 0; i != db_size; ++i) {
Andre Eisenbach7ee02bd2016-04-11 14:50:41 -0700174 if (feature == interop_addr_database[i].feature &&
Myles Watson4451b3b2016-11-09 10:20:44 -0800175 memcmp(addr, &interop_addr_database[i].addr,
176 interop_addr_database[i].length) == 0) {
Andre Eisenbach7927f682015-07-02 16:14:28 -0700177 return true;
178 }
179 }
180
181 return false;
182}