1 /****************************************************************************** 2 * 3 * Copyright (C) 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 <assert.h> 22 #include <string.h> // For memcmp 23 24 #include "btcore/include/module.h" 25 #include "device/include/interop.h" 26 #include "device/include/interop_database.h" 27 #include "osi/include/allocator.h" 28 #include "osi/include/list.h" 29 #include "osi/include/log.h" 30 31 #define CASE_RETURN_STR(const) case const: return #const; 32 33 static list_t *interop_list = NULL; 34 35 static const char* interop_feature_string_(const interop_feature_t feature); 36 static void interop_free_entry_(void *data); 37 static void interop_lazy_init_(void); 38 static bool interop_match_fixed_(const interop_feature_t feature, const bt_bdaddr_t *addr); 39 static bool interop_match_dynamic_(const interop_feature_t feature, const bt_bdaddr_t *addr); 40 41 // Interface functions 42 43 bool interop_match_addr(const interop_feature_t feature, const bt_bdaddr_t *addr) { 44 assert(addr); 45 46 if (interop_match_fixed_(feature, addr) || interop_match_dynamic_(feature, addr)) { 47 char bdstr[20] = {0}; 48 LOG_WARN(LOG_TAG, "%s() Device %s is a match for interop workaround %s.", 49 __func__, bdaddr_to_string(addr, bdstr, sizeof(bdstr)), 50 interop_feature_string_(feature)); 51 return true; 52 } 53 54 return false; 55 } 56 57 bool interop_match_name(const interop_feature_t feature, const char *name) { 58 assert(name); 59 60 const size_t db_size = sizeof(interop_name_database) / sizeof(interop_name_entry_t); 61 for (size_t i = 0; i != db_size; ++i) { 62 if (feature == interop_name_database[i].feature && 63 strlen(name) >= interop_name_database[i].length && 64 strncmp(name, interop_name_database[i].name, interop_name_database[i].length) == 0) { 65 return true; 66 } 67 } 68 69 return false; 70 } 71 72 void interop_database_add(const uint16_t feature, const bt_bdaddr_t *addr, size_t length) { 73 assert(addr); 74 assert(length > 0); 75 assert(length < sizeof(bt_bdaddr_t)); 76 77 interop_addr_entry_t *entry = osi_calloc(sizeof(interop_addr_entry_t)); 78 memcpy(&entry->addr, addr, length); 79 entry->feature = feature; 80 entry->length = length; 81 82 interop_lazy_init_(); 83 list_append(interop_list, entry); 84 } 85 86 void interop_database_clear() { 87 if (interop_list) 88 list_clear(interop_list); 89 } 90 91 // Module life-cycle functions 92 93 static future_t *interop_clean_up(void) { 94 list_free(interop_list); 95 interop_list = NULL; 96 return future_new_immediate(FUTURE_SUCCESS); 97 } 98 99 EXPORT_SYMBOL module_t interop_module = { 100 .name = INTEROP_MODULE, 101 .init = NULL, 102 .start_up = NULL, 103 .shut_down = NULL, 104 .clean_up = interop_clean_up, 105 .dependencies = {NULL}, 106 }; 107 108 // Local functions 109 110 static const char* interop_feature_string_(const interop_feature_t feature) { 111 switch (feature) { 112 CASE_RETURN_STR(INTEROP_DISABLE_LE_SECURE_CONNECTIONS) 113 CASE_RETURN_STR(INTEROP_AUTO_RETRY_PAIRING) 114 CASE_RETURN_STR(INTEROP_DISABLE_ABSOLUTE_VOLUME) 115 CASE_RETURN_STR(INTEROP_DISABLE_AUTO_PAIRING) 116 CASE_RETURN_STR(INTEROP_KEYBOARD_REQUIRES_FIXED_PIN) 117 CASE_RETURN_STR(INTEROP_2MBPS_LINK_ONLY) 118 } 119 120 return "UNKNOWN"; 121 } 122 123 static void interop_free_entry_(void *data) { 124 interop_addr_entry_t *entry = (interop_addr_entry_t *)data; 125 osi_free(entry); 126 } 127 128 static void interop_lazy_init_(void) { 129 if (interop_list == NULL) { 130 interop_list = list_new(interop_free_entry_); 131 } 132 } 133 134 static bool interop_match_dynamic_(const interop_feature_t feature, const bt_bdaddr_t *addr) { 135 if (interop_list == NULL || list_length(interop_list) == 0) 136 return false; 137 138 const list_node_t *node = list_begin(interop_list); 139 while (node != list_end(interop_list)) { 140 interop_addr_entry_t *entry = list_node(node); 141 assert(entry); 142 143 if (feature == entry->feature && memcmp(addr, &entry->addr, entry->length) == 0) 144 return true; 145 146 node = list_next(node); 147 } 148 return false; 149 } 150 151 static bool interop_match_fixed_(const interop_feature_t feature, const bt_bdaddr_t *addr) { 152 assert(addr); 153 154 const size_t db_size = sizeof(interop_addr_database) / sizeof(interop_addr_entry_t); 155 for (size_t i = 0; i != db_size; ++i) { 156 if (feature == interop_addr_database[i].feature && 157 memcmp(addr, &interop_addr_database[i].addr, interop_addr_database[i].length) == 0) { 158 return true; 159 } 160 } 161 162 return false; 163 } 164