Loading system/btif/src/bluetooth.c +5 −2 Original line number Diff line number Diff line Loading @@ -50,9 +50,10 @@ #include "btsnoop.h" #include "btsnoop_mem.h" #include "bt_utils.h" #include "osi/include/osi.h" #include "device/include/interop.h" #include "osi/include/allocation_tracker.h" #include "osi/include/log.h" #include "osi/include/osi.h" #include "stack_manager.h" #include "btif_config.h" Loading Loading @@ -456,7 +457,9 @@ static const bt_interface_t bluetoothInterface = { set_os_callouts, read_energy_info, dump, config_clear config_clear, interop_database_clear, interop_database_add, }; const bt_interface_t* bluetooth__get_bluetooth_interface () Loading system/device/include/interop.h +12 −2 Original line number Diff line number Diff line Loading @@ -22,11 +22,13 @@ #include "btcore/include/bdaddr.h" static const char INTEROP_MODULE[] = "interop_module"; typedef enum { // Disable secure connections // This is for pre BT 4.1/2 devices that do not handle secure mode // very well. INTEROP_DISABLE_LE_SECURE_CONNECTIONS, INTEROP_DISABLE_LE_SECURE_CONNECTIONS = 0, // Some devices have proven problematic during the pairing process, often // requiring multiple retries to complete pairing. To avoid degrading the user Loading @@ -38,5 +40,13 @@ typedef enum { // Check if a given |addr| matches a known interoperability workaround as identified // by the |interop_feature_t| enum. This API is used for simple address based lookups // where more information is not available. No look-ups or random address resolution // is performed on |addr|. // are performed on |addr|. bool interop_match(const interop_feature_t feature, const bt_bdaddr_t *addr); // Add a dynamic interop database entry for a device matching the first |length| bytes // of |addr|, implementing the workaround identified by |feature|. |addr| may not be // null and |length| must be greater than 0 and less than sizeof(bt_bdaddr_t). void interop_database_add(const interop_feature_t feature, const bt_bdaddr_t *addr, size_t length); // Clear the dynamic portion of the interoperability workaround database. void interop_database_clear(void); system/device/include/interop_database.h +1 −1 Original line number Diff line number Diff line Loading @@ -22,7 +22,7 @@ typedef struct { bt_bdaddr_t addr; uint8_t len; size_t length; interop_feature_t feature; } interop_entry_t; Loading system/device/src/interop.c +96 −6 Original line number Diff line number Diff line Loading @@ -21,13 +21,78 @@ #include <assert.h> #include <string.h> // For memcmp #include "btcore/include/module.h" #include "device/include/interop.h" #include "device/include/interop_database.h" #include "osi/include/allocator.h" #include "osi/include/list.h" #include "osi/include/log.h" #define CASE_RETURN_STR(const) case const: return #const; static const char* interop_feature_string(const interop_feature_t feature) { static list_t *interop_list = NULL; static const char* interop_feature_string_(const interop_feature_t feature); static void interop_free_entry_(void *data); static void interop_lazy_init_(void); static bool interop_match_fixed_(const interop_feature_t feature, const bt_bdaddr_t *addr); static bool interop_match_dynamic_(const interop_feature_t feature, const bt_bdaddr_t *addr); // Interface functions bool interop_match(const interop_feature_t feature, const bt_bdaddr_t *addr) { assert(addr); if (interop_match_fixed_(feature, addr) || interop_match_dynamic_(feature, addr)) { char bdstr[20] = {0}; LOG_WARN("%s() Device %s is a match for interop workaround %s.", __func__, bdaddr_to_string(addr, bdstr, sizeof(bdstr)), interop_feature_string_(feature)); return true; } return false; } void interop_database_add(const interop_feature_t feature, const bt_bdaddr_t *addr, size_t length) { assert(addr); assert(length > 0); assert(length < sizeof(bt_bdaddr_t)); interop_entry_t *entry = osi_calloc(sizeof(interop_entry_t)); memcpy(&entry->addr, addr, length); entry->feature = feature; entry->length = length; interop_lazy_init_(); list_append(interop_list, entry); } void interop_database_clear() { if (interop_list) list_clear(interop_list); } // Module life-cycle functions static future_t *interop_clean_up(void) { list_free(interop_list); interop_list = NULL; return future_new_immediate(FUTURE_SUCCESS); } const module_t interop_module = { .name = INTEROP_MODULE, .init = NULL, .start_up = NULL, .shut_down = NULL, .clean_up = interop_clean_up, .dependencies = {NULL}, }; // Local functions static const char* interop_feature_string_(const interop_feature_t feature) { switch (feature) { CASE_RETURN_STR(INTEROP_DISABLE_LE_SECURE_CONNECTIONS) CASE_RETURN_STR(INTEROP_AUTO_RETRY_PAIRING) Loading @@ -36,19 +101,44 @@ static const char* interop_feature_string(const interop_feature_t feature) { return "UNKNOWN"; } // Interface functions static void interop_free_entry_(void *data) { interop_entry_t *entry = (interop_entry_t *)data; osi_free(entry); } bool interop_match(const interop_feature_t feature, const bt_bdaddr_t *addr) { static void interop_lazy_init_(void) { if (interop_list == NULL) { interop_list = list_new(interop_free_entry_); } } static bool interop_match_dynamic_(const interop_feature_t feature, const bt_bdaddr_t *addr) { if (interop_list == NULL || list_length(interop_list) == 0) return false; const list_node_t *node = list_begin(interop_list); while (node != list_end(interop_list)) { interop_entry_t *entry = list_node(node); assert(entry); if (feature == entry->feature && memcmp(addr, &entry->addr, entry->length) == 0) return true; node = list_next(node); } return false; } static bool interop_match_fixed_(const interop_feature_t feature, const bt_bdaddr_t *addr) { assert(addr); const size_t db_size = sizeof(interop_database) / sizeof(interop_entry_t); for (size_t i = 0; i != db_size; ++i) { if (feature == interop_database[i].feature && memcmp(addr, &interop_database[i].addr, interop_database[i].len) == 0) { memcmp(addr, &interop_database[i].addr, interop_database[i].length) == 0) { char bdstr[20] = {0}; LOG_WARN("%s() Device %s is a match for interop workaround %s", __func__, bdaddr_to_string(addr, bdstr, sizeof(bdstr)), interop_feature_string(feature)); bdaddr_to_string(addr, bdstr, sizeof(bdstr)), interop_feature_string_(feature)); return true; } } Loading system/device/test/interop_test.cpp +20 −0 Original line number Diff line number Diff line Loading @@ -42,3 +42,23 @@ TEST(InteropTest, test_lookup_miss) { EXPECT_FALSE(interop_match(INTEROP_AUTO_RETRY_PAIRING, &test_address)); } TEST(InteropTest, test_dynamic) { bt_bdaddr_t test_address; string_to_bdaddr("11:22:33:44:55:66", &test_address); EXPECT_FALSE(interop_match(INTEROP_DISABLE_LE_SECURE_CONNECTIONS, &test_address)); interop_database_add(INTEROP_DISABLE_LE_SECURE_CONNECTIONS, &test_address, 3); EXPECT_TRUE(interop_match(INTEROP_DISABLE_LE_SECURE_CONNECTIONS, &test_address)); EXPECT_FALSE(interop_match(INTEROP_AUTO_RETRY_PAIRING, &test_address)); string_to_bdaddr("66:55:44:33:22:11", &test_address); EXPECT_FALSE(interop_match(INTEROP_AUTO_RETRY_PAIRING, &test_address)); interop_database_add(INTEROP_AUTO_RETRY_PAIRING, &test_address, 3); EXPECT_TRUE(interop_match(INTEROP_AUTO_RETRY_PAIRING, &test_address)); EXPECT_FALSE(interop_match(INTEROP_DISABLE_LE_SECURE_CONNECTIONS, &test_address)); interop_database_clear(); EXPECT_FALSE(interop_match(INTEROP_AUTO_RETRY_PAIRING, &test_address)); } Loading
system/btif/src/bluetooth.c +5 −2 Original line number Diff line number Diff line Loading @@ -50,9 +50,10 @@ #include "btsnoop.h" #include "btsnoop_mem.h" #include "bt_utils.h" #include "osi/include/osi.h" #include "device/include/interop.h" #include "osi/include/allocation_tracker.h" #include "osi/include/log.h" #include "osi/include/osi.h" #include "stack_manager.h" #include "btif_config.h" Loading Loading @@ -456,7 +457,9 @@ static const bt_interface_t bluetoothInterface = { set_os_callouts, read_energy_info, dump, config_clear config_clear, interop_database_clear, interop_database_add, }; const bt_interface_t* bluetooth__get_bluetooth_interface () Loading
system/device/include/interop.h +12 −2 Original line number Diff line number Diff line Loading @@ -22,11 +22,13 @@ #include "btcore/include/bdaddr.h" static const char INTEROP_MODULE[] = "interop_module"; typedef enum { // Disable secure connections // This is for pre BT 4.1/2 devices that do not handle secure mode // very well. INTEROP_DISABLE_LE_SECURE_CONNECTIONS, INTEROP_DISABLE_LE_SECURE_CONNECTIONS = 0, // Some devices have proven problematic during the pairing process, often // requiring multiple retries to complete pairing. To avoid degrading the user Loading @@ -38,5 +40,13 @@ typedef enum { // Check if a given |addr| matches a known interoperability workaround as identified // by the |interop_feature_t| enum. This API is used for simple address based lookups // where more information is not available. No look-ups or random address resolution // is performed on |addr|. // are performed on |addr|. bool interop_match(const interop_feature_t feature, const bt_bdaddr_t *addr); // Add a dynamic interop database entry for a device matching the first |length| bytes // of |addr|, implementing the workaround identified by |feature|. |addr| may not be // null and |length| must be greater than 0 and less than sizeof(bt_bdaddr_t). void interop_database_add(const interop_feature_t feature, const bt_bdaddr_t *addr, size_t length); // Clear the dynamic portion of the interoperability workaround database. void interop_database_clear(void);
system/device/include/interop_database.h +1 −1 Original line number Diff line number Diff line Loading @@ -22,7 +22,7 @@ typedef struct { bt_bdaddr_t addr; uint8_t len; size_t length; interop_feature_t feature; } interop_entry_t; Loading
system/device/src/interop.c +96 −6 Original line number Diff line number Diff line Loading @@ -21,13 +21,78 @@ #include <assert.h> #include <string.h> // For memcmp #include "btcore/include/module.h" #include "device/include/interop.h" #include "device/include/interop_database.h" #include "osi/include/allocator.h" #include "osi/include/list.h" #include "osi/include/log.h" #define CASE_RETURN_STR(const) case const: return #const; static const char* interop_feature_string(const interop_feature_t feature) { static list_t *interop_list = NULL; static const char* interop_feature_string_(const interop_feature_t feature); static void interop_free_entry_(void *data); static void interop_lazy_init_(void); static bool interop_match_fixed_(const interop_feature_t feature, const bt_bdaddr_t *addr); static bool interop_match_dynamic_(const interop_feature_t feature, const bt_bdaddr_t *addr); // Interface functions bool interop_match(const interop_feature_t feature, const bt_bdaddr_t *addr) { assert(addr); if (interop_match_fixed_(feature, addr) || interop_match_dynamic_(feature, addr)) { char bdstr[20] = {0}; LOG_WARN("%s() Device %s is a match for interop workaround %s.", __func__, bdaddr_to_string(addr, bdstr, sizeof(bdstr)), interop_feature_string_(feature)); return true; } return false; } void interop_database_add(const interop_feature_t feature, const bt_bdaddr_t *addr, size_t length) { assert(addr); assert(length > 0); assert(length < sizeof(bt_bdaddr_t)); interop_entry_t *entry = osi_calloc(sizeof(interop_entry_t)); memcpy(&entry->addr, addr, length); entry->feature = feature; entry->length = length; interop_lazy_init_(); list_append(interop_list, entry); } void interop_database_clear() { if (interop_list) list_clear(interop_list); } // Module life-cycle functions static future_t *interop_clean_up(void) { list_free(interop_list); interop_list = NULL; return future_new_immediate(FUTURE_SUCCESS); } const module_t interop_module = { .name = INTEROP_MODULE, .init = NULL, .start_up = NULL, .shut_down = NULL, .clean_up = interop_clean_up, .dependencies = {NULL}, }; // Local functions static const char* interop_feature_string_(const interop_feature_t feature) { switch (feature) { CASE_RETURN_STR(INTEROP_DISABLE_LE_SECURE_CONNECTIONS) CASE_RETURN_STR(INTEROP_AUTO_RETRY_PAIRING) Loading @@ -36,19 +101,44 @@ static const char* interop_feature_string(const interop_feature_t feature) { return "UNKNOWN"; } // Interface functions static void interop_free_entry_(void *data) { interop_entry_t *entry = (interop_entry_t *)data; osi_free(entry); } bool interop_match(const interop_feature_t feature, const bt_bdaddr_t *addr) { static void interop_lazy_init_(void) { if (interop_list == NULL) { interop_list = list_new(interop_free_entry_); } } static bool interop_match_dynamic_(const interop_feature_t feature, const bt_bdaddr_t *addr) { if (interop_list == NULL || list_length(interop_list) == 0) return false; const list_node_t *node = list_begin(interop_list); while (node != list_end(interop_list)) { interop_entry_t *entry = list_node(node); assert(entry); if (feature == entry->feature && memcmp(addr, &entry->addr, entry->length) == 0) return true; node = list_next(node); } return false; } static bool interop_match_fixed_(const interop_feature_t feature, const bt_bdaddr_t *addr) { assert(addr); const size_t db_size = sizeof(interop_database) / sizeof(interop_entry_t); for (size_t i = 0; i != db_size; ++i) { if (feature == interop_database[i].feature && memcmp(addr, &interop_database[i].addr, interop_database[i].len) == 0) { memcmp(addr, &interop_database[i].addr, interop_database[i].length) == 0) { char bdstr[20] = {0}; LOG_WARN("%s() Device %s is a match for interop workaround %s", __func__, bdaddr_to_string(addr, bdstr, sizeof(bdstr)), interop_feature_string(feature)); bdaddr_to_string(addr, bdstr, sizeof(bdstr)), interop_feature_string_(feature)); return true; } } Loading
system/device/test/interop_test.cpp +20 −0 Original line number Diff line number Diff line Loading @@ -42,3 +42,23 @@ TEST(InteropTest, test_lookup_miss) { EXPECT_FALSE(interop_match(INTEROP_AUTO_RETRY_PAIRING, &test_address)); } TEST(InteropTest, test_dynamic) { bt_bdaddr_t test_address; string_to_bdaddr("11:22:33:44:55:66", &test_address); EXPECT_FALSE(interop_match(INTEROP_DISABLE_LE_SECURE_CONNECTIONS, &test_address)); interop_database_add(INTEROP_DISABLE_LE_SECURE_CONNECTIONS, &test_address, 3); EXPECT_TRUE(interop_match(INTEROP_DISABLE_LE_SECURE_CONNECTIONS, &test_address)); EXPECT_FALSE(interop_match(INTEROP_AUTO_RETRY_PAIRING, &test_address)); string_to_bdaddr("66:55:44:33:22:11", &test_address); EXPECT_FALSE(interop_match(INTEROP_AUTO_RETRY_PAIRING, &test_address)); interop_database_add(INTEROP_AUTO_RETRY_PAIRING, &test_address, 3); EXPECT_TRUE(interop_match(INTEROP_AUTO_RETRY_PAIRING, &test_address)); EXPECT_FALSE(interop_match(INTEROP_DISABLE_LE_SECURE_CONNECTIONS, &test_address)); interop_database_clear(); EXPECT_FALSE(interop_match(INTEROP_AUTO_RETRY_PAIRING, &test_address)); }