/* Copyright Statement: * * * * This software/firmware and related documentation ("MediaTek Software") are * * protected under relevant copyright laws. The information contained herein * * is confidential and proprietary to MediaTek Inc. and/or its licensors. * * Without the prior written permission of MediaTek inc. and/or its licensors, * * any reproduction, modification, use or disclosure of MediaTek Software, * * and information contained herein, in whole or in part, shall be strictly * * prohibited. * * * * MediaTek Inc. (C) 2016. All rights reserved. * * * * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES * * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE") * * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER * * ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL * * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED * * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR * * NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH * * RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, * * INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER * * AGREES TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING * * THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE * * RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED * * IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY * * MEDIATEK SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM * * TO A PARTICULAR STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE * * REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE * * MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE, AT MEDIATEK'S OPTION, TO * * REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE * * LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO MEDIATEK FOR SUCH * * MEDIATEK SOFTWARE AT ISSUE. * * * * The following software/firmware and/or related documentation ("MediaTek * * Software") * * have been modified by MediaTek Inc. All revisions are subject to any * * receiver's applicable license agreements with MediaTek Inc. * */ /****************************************************************************** * * This file contains functions for the MTK defined interop function * ******************************************************************************/ #define LOG_TAG "bt_device_interop_mtk" #include #include #include #include #include #include "interop_mtk.h" #if MTK_INTEROP_CONF == 1 #if defined(MTK_INTEROP_EXTENSION) && (MTK_INTEROP_EXTENSION == TRUE) #include #include #include "btif_config.h" #include "btm_api.h" #include "btm_api_types.h" #include "module.h" #include "osi/include/config.h" #include "osi/include/future.h" using base::StringPrintf; #define MTK_STACK_CONFIG_VALUE_SEPARATOR "," #define MTK_STACK_CONFIG_NAME_VALUE_MAX 1024 #define MTK_STACK_CONFIG_VERSION 0x7 #define MTK_STACK_CONFIG_VERSION_LMP_VER 0x4 #define MTK_STACK_CONFIG_VERSION_MFCT 0x2 #define MTK_STACK_CONFIG_VERSION_LMP_SUBVER 0x1 static std::unique_ptr config_org; static std::unique_ptr config_ext; const char* BLACKLIST_ADDR_KEY = "AddressBlacklist"; const char* BLACKLIST_NAME_KEY = "ExactNameBlacklist"; const char* BLACKLIST_PARTIAL_NAME_KEY = "PartialNameBlacklist"; const char* BLACKLIST_VERSION_KEY = "VersionBlacklist"; /** M: New feature: add device information to black list {@ */ const char* BTIOT_CONFIG_FILE_NAME = "/etc/bluetooth/bt_mtk_iot_list.conf"; const char* BTIOT_UPDATE_FILE_NAME = "/data/misc/bluedroid/bt_mtk_iot_list.conf"; /**@}*/ static const std::string* get_blacklist_content(const config_t& config, const char* section, const std::string& key) { return config_get_string(config, section, key, NULL); } static void set_blacklist_content(const char* section, const std::string& key, const char* strvalue) { LOG(INFO) << StringPrintf("%s: %s save %s: %s", LOG_TAG, __func__, section, strvalue); config_set_string(config_ext.get(), section, key, strvalue); config_save(*config_ext, BTIOT_UPDATE_FILE_NAME); } static future_t* init() { // TODO(armansito): Find a better way than searching by a hardcoded path. #if defined(OS_GENERIC) const char* path = "bt_mtk_iot_list.conf"; #else // !defined(OS_GENERIC) const char* path = "/etc/bluetooth/bt_mtk_iot_list.conf"; #endif // defined(OS_GENERIC) /** M: New feature: add device information to black list {@ */ config_ext = config_new(BTIOT_UPDATE_FILE_NAME); if (!config_ext) { int fd; mode_t old = umask(0007); fd = open(BTIOT_UPDATE_FILE_NAME, O_WRONLY | O_CREAT | O_TRUNC, 00660); umask(old); if (fd < 0) { LOG(INFO) << StringPrintf("%s: %s file >%s< creat fail", LOG_TAG, __func__, BTIOT_UPDATE_FILE_NAME); return future_new_immediate(FUTURE_FAIL); } close(fd); config_ext = config_new(BTIOT_UPDATE_FILE_NAME); } config_org = config_new(path); if (!config_org) { LOG(INFO) << StringPrintf("%s: %s file >%s< not found", LOG_TAG, __func__, path); return future_new_immediate(FUTURE_FAIL); } /**@}*/ return future_new_immediate(FUTURE_SUCCESS); } static future_t* clean_up() { config_org.reset(); config_ext.reset(); return future_new_immediate(FUTURE_SUCCESS); } EXPORT_SYMBOL extern const module_t mtk_iot_list_module = { .name = MTK_IOT_LIST_MODULE, .init = init, .start_up = NULL, .shut_down = NULL, .clean_up = clean_up, .dependencies = {NULL}}; bt_status_t btmtk_get_ble_device_name(const RawAddress* addr, BD_NAME bd_name) { if (addr) { std::string addrstr = addr->ToString(); const char* bdstr = addrstr.c_str(); int length = BD_NAME_LEN; bool ret = btif_config_get_str(bdstr, "Name", reinterpret_cast(bd_name), &length); return ret ? BT_STATUS_SUCCESS : BT_STATUS_FAIL; } return BT_STATUS_FAIL; } bool interop_mtk_match_addr_byconfig(const config_t& config, const char* section, const RawAddress* addr) { char* token; char* start_ptr = NULL; const std::string* value; std::string addrstr = addr->ToString(); const char* bdstr = addrstr.c_str(); char addr_list[MTK_STACK_CONFIG_NAME_VALUE_MAX] = {0}; int copy_len; if ((value = get_blacklist_content(config, section, BLACKLIST_ADDR_KEY)) != NULL) { VLOG(2) << StringPrintf("%s:[%s] check %s in %s", __func__, section, bdstr, value->c_str()); if (value->length() < MTK_STACK_CONFIG_NAME_VALUE_MAX) copy_len = value->length(); else copy_len = MTK_STACK_CONFIG_NAME_VALUE_MAX - 1; strncpy(addr_list, value->c_str(), copy_len); token = strtok_r(addr_list, MTK_STACK_CONFIG_VALUE_SEPARATOR, &start_ptr); while (token != NULL) { if (strncasecmp(bdstr, token, strlen(token)) == 0) { LOG(INFO) << StringPrintf("%s:[%s] %s got matched", __func__, section, bdstr); return TRUE; } token = strtok_r(NULL, MTK_STACK_CONFIG_VALUE_SEPARATOR, &start_ptr); } } return FALSE; } bool interop_mtk_match_addr(const char* section, const RawAddress* addr) { if (config_org == NULL || section == NULL || addr == NULL) return FALSE; bool result; result = interop_mtk_match_addr_byconfig(*config_org, section, addr); if (result) return TRUE; if (config_ext != NULL) result = interop_mtk_match_addr_byconfig(*config_ext, section, addr); if (result) return TRUE; return FALSE; } /** M: New feature: framework get black list information {@ */ bool interop_mtk_match_name_byconfig(const config_t& config, const char* section, const char* name) { char* token; char* start_ptr = NULL; const std::string* value; char name_list[MTK_STACK_CONFIG_NAME_VALUE_MAX] = {0}; int copy_len; if ((value = get_blacklist_content(config, section, BLACKLIST_NAME_KEY)) != NULL) { VLOG(2) << StringPrintf("%s:[%s] check %s in %s", __func__, section, name, value->c_str()); if (value->length() < MTK_STACK_CONFIG_NAME_VALUE_MAX) copy_len = value->length(); else copy_len = MTK_STACK_CONFIG_NAME_VALUE_MAX - 1; strncpy(name_list, value->c_str(), copy_len); token = strtok_r(name_list, MTK_STACK_CONFIG_VALUE_SEPARATOR, &start_ptr); while (token != NULL) { if (!strcmp(token, name)) { LOG(INFO) << StringPrintf("%s:[%s] %s got matched", __func__, section, name); return TRUE; } token = strtok_r(NULL, MTK_STACK_CONFIG_VALUE_SEPARATOR, &start_ptr); } } memset(name_list, 0, sizeof(name_list)); if ((value = get_blacklist_content(config, section, BLACKLIST_PARTIAL_NAME_KEY)) != NULL) { if (value->length() < MTK_STACK_CONFIG_NAME_VALUE_MAX) copy_len = value->length(); else copy_len = MTK_STACK_CONFIG_NAME_VALUE_MAX - 1; strncpy(name_list, value->c_str(), copy_len); LOG(INFO) << StringPrintf("%s:[%s] check name %s in partial name list %s", __func__, section, name, name_list); token = strtok_r(name_list, MTK_STACK_CONFIG_VALUE_SEPARATOR, &start_ptr); while (token != NULL) { if (strstr(name, token) != NULL) { LOG(INFO) << StringPrintf("%s:[%s] %s got matched", __func__, section, name); return TRUE; } token = strtok_r(NULL, MTK_STACK_CONFIG_VALUE_SEPARATOR, &start_ptr); } } return FALSE; } /**@}*/ bool interop_mtk_match_name_byaddr(const config_t& config, const char* section, const RawAddress* addr) { char* dev_name_str; BD_NAME remote_name = {0}; bool result; dev_name_str = BTM_SecReadDevName(*addr); // need to load ble device name from config if (dev_name_str == NULL || dev_name_str[0] == '\0') { dev_name_str = reinterpret_cast(remote_name); btmtk_get_ble_device_name(addr, remote_name); } if (dev_name_str == NULL || dev_name_str[0] == '\0') return FALSE; result = interop_mtk_match_name_byconfig(config, section, dev_name_str); return result; } bool interop_mtk_match_name(const char* section, const RawAddress* addr) { if (config_org == NULL || section == NULL || addr == NULL) return FALSE; bool result; result = interop_mtk_match_name_byaddr(*config_org, section, addr); if (result) return TRUE; if (config_ext != NULL) result = interop_mtk_match_name_byaddr(*config_ext, section, addr); if (result) return TRUE; return FALSE; } bool interop_mtk_match_name(const char* section, const char* name) { if (config_org == NULL || section == NULL || name == NULL) return FALSE; bool result; result = interop_mtk_match_name_byconfig(*config_org, section, name); if (result) return TRUE; if (config_ext != NULL) result = interop_mtk_match_name_byconfig(*config_ext, section, name); if (result) return TRUE; return FALSE; } bool interop_mtk_match_addr_name(const char* section, const RawAddress* addr) { return interop_mtk_match_addr(section, addr) || interop_mtk_match_name(section, addr); } char *utoa(unsigned int value, char * str, int radix, int len) { const char * format = NULL; switch(radix) { case 8: format = "%o"; break; case 10: format = "%u"; break; case 16: if (len == 2) format = "%02x"; else format = "%04x"; break; } if(format == NULL) return str; int size = sprintf(str, format, value); return &str[size]; } bool interop_mtk_match_ver_byconfig(const config_t& config, const char* section, const uint8_t state, const uint8_t lmp_ver, const uint16_t mfct_set, const uint16_t lmp_subver) { char* token; char* start_ptr = NULL; const std::string* value; int copy_len; char ver_list[MTK_STACK_CONFIG_NAME_VALUE_MAX] = {0}; char pattern[13] = {0}; char buffer[5]; memset(buffer, '\0', sizeof(buffer)); if (state & MTK_STACK_CONFIG_VERSION_LMP_VER) { utoa(lmp_ver, buffer, 16, 2); strcat(pattern, buffer); strcat(pattern, ":"); memset(buffer, '\0', sizeof(buffer)); } if (state & MTK_STACK_CONFIG_VERSION_MFCT) { utoa(mfct_set, buffer, 16, 4); strcat(pattern, buffer); strcat(pattern, ":"); memset(buffer, '\0', sizeof(buffer)); } if (state & MTK_STACK_CONFIG_VERSION_LMP_SUBVER) { utoa(lmp_subver, buffer, 16, 4); strcat(pattern, buffer); } if ((value = get_blacklist_content(config, section, BLACKLIST_VERSION_KEY)) != NULL) { VLOG(2) << StringPrintf("%s:[%s] check %s in %s", __func__, section, pattern, value->c_str()); if (value->length() < MTK_STACK_CONFIG_NAME_VALUE_MAX) copy_len = value->length(); else copy_len = MTK_STACK_CONFIG_NAME_VALUE_MAX - 1; strncpy(ver_list, value->c_str(), copy_len); token = strtok_r(ver_list, MTK_STACK_CONFIG_VALUE_SEPARATOR, &start_ptr); while (token != NULL) { if (strstr(token, pattern) != NULL) { LOG(INFO) << StringPrintf("%s:[%s] %s got matched", __func__, section, pattern); return TRUE; } token = strtok_r(NULL, MTK_STACK_CONFIG_VALUE_SEPARATOR, &start_ptr); } } return FALSE; } bool interop_mtk_match_ver_byaddr(const char* section, const RawAddress* addr, const uint8_t state) { if (config_org == NULL || section == NULL || addr == NULL) return FALSE; bool result = FALSE; uint8_t lmp_ver = 0; uint16_t mfct_set = 0; uint16_t lmp_subver = 0; if (!BTM_ReadRemoteVersion(*addr, &lmp_ver, &mfct_set, &lmp_subver)) { LOG(INFO) << StringPrintf("%s: %s BTM_ReadRemoteVersion", LOG_TAG, __func__); return FALSE; } if (0 == lmp_ver && 0 == mfct_set && 0 == lmp_subver) { LOG(INFO) << StringPrintf("%s: %s get remote version fail", LOG_TAG, __func__); return FALSE; } if (interop_mtk_match_ver_byconfig(*config_org, section, state, lmp_ver, mfct_set, lmp_subver)) return TRUE; if (config_ext != NULL) result = interop_mtk_match_ver_byconfig(*config_ext, section, state, lmp_ver, mfct_set, lmp_subver); return result; } bool interop_mtk_match_lmp_ver(const char* section, const RawAddress* addr) { return interop_mtk_match_ver_byaddr(section, addr, MTK_STACK_CONFIG_VERSION_LMP_VER); } bool interop_mtk_match_mfct(const char* section, const RawAddress* addr) { return interop_mtk_match_ver_byaddr(section, addr, MTK_STACK_CONFIG_VERSION_MFCT); } bool interop_mtk_match_lmp_subver(const char* section, const RawAddress* addr) { return interop_mtk_match_ver_byaddr(section, addr, MTK_STACK_CONFIG_VERSION_LMP_SUBVER); } bool interop_mtk_match_ver(const char* section, const RawAddress* addr) { return interop_mtk_match_ver_byaddr(section, addr, MTK_STACK_CONFIG_VERSION); } bool interop_mtk_match_any(const char* section, const RawAddress* addr) { return interop_mtk_match_addr(section, addr) || interop_mtk_match_name(section, addr) || interop_mtk_match_ver(section, addr); } /** M: New feature: add device information to black list {@ */ bool interop_mtk_set_addr(const char* section, const RawAddress* addr, int size) { if (config_ext == NULL || section == NULL || addr == NULL) return FALSE; const std::string* value; std::string addrstr = addr->ToString(); const char* bdstr = addrstr.c_str(); char addr_list[MTK_STACK_CONFIG_NAME_VALUE_MAX] = {0}; int value_len = 0; int addr_len = 0; int addrsize = size * 2 + size - 1; char addr_add[18] = {0}; if (interop_mtk_match_addr_byconfig(*config_org, section, addr)) return TRUE; if (interop_mtk_match_addr_byconfig(*config_ext, section, addr)) return TRUE; if ((value = get_blacklist_content(*config_ext, section, BLACKLIST_ADDR_KEY)) != NULL) { VLOG(2) << StringPrintf("%s:[%s] check %s in %s", __func__, section, addr_add, value->c_str()); if (value->length() < MTK_STACK_CONFIG_NAME_VALUE_MAX) value_len = value->length(); else value_len = MTK_STACK_CONFIG_NAME_VALUE_MAX - 1; strncpy(addr_list, value->c_str(), value_len); strncpy(addr_add, bdstr, addrsize); addr_len = strlen(addr_add); if ((MTK_STACK_CONFIG_NAME_VALUE_MAX - value_len) < addr_len + 1) { LOG(INFO) << StringPrintf("%s:[%s][size:%d] %s[len:%d] too long", __func__, section, value_len, addr_add, addr_len); return FALSE; } addr_list[value_len] = ','; strcpy(addr_list + value_len + 1, addr_add); set_blacklist_content(section, BLACKLIST_ADDR_KEY, addr_list); return TRUE; } else { strncpy(addr_list, bdstr, addrsize); set_blacklist_content(section, BLACKLIST_ADDR_KEY, addr_list); return TRUE; } } bool interop_mtk_set_name_bykey(const char* section, const char* name, bool partialname) { const std::string* value; const char* key; char name_list[MTK_STACK_CONFIG_NAME_VALUE_MAX]= {0}; int value_len = 0; int name_len = 0; if (interop_mtk_match_name_byconfig(*config_org, section, name)) return TRUE; if (interop_mtk_match_name_byconfig(*config_ext, section, name)) return TRUE; if (partialname) key = BLACKLIST_PARTIAL_NAME_KEY; else key = BLACKLIST_NAME_KEY; value = get_blacklist_content(*config_ext, section, key); if (value != NULL) { LOG(INFO) << StringPrintf("%s:[%s] check %s in %s", __func__, section, name, value->c_str()); if (value->length() < MTK_STACK_CONFIG_NAME_VALUE_MAX) value_len = value->length(); else value_len = MTK_STACK_CONFIG_NAME_VALUE_MAX - 1; name_len = strlen(name); if ((MTK_STACK_CONFIG_NAME_VALUE_MAX - value_len) < name_len + 1) { LOG(INFO) << StringPrintf("%s:[%s][size:%d] %s[len:%d] too long", __func__, section, value_len, name, name_len); return FALSE; } strncpy(name_list, value->c_str(), value_len); name_list[value_len] = ','; strcpy(name_list + value_len + 1, name); set_blacklist_content(section, key, name_list); return TRUE; } else { strcpy(name_list, name); set_blacklist_content(section, key, name_list); return TRUE; } } bool interop_mtk_set_name(const char* section, const char* name) { if (config_ext == NULL || section == NULL || name == NULL) return FALSE; return interop_mtk_set_name_bykey(section, name, FALSE); } bool interop_mtk_set_partial_name(const char* section, const char* name) { if (config_ext == NULL || section == NULL || name == NULL) return FALSE; return interop_mtk_set_name_bykey(section, name, TRUE); } bool interop_mtk_set_ver(const char* section, const RawAddress* addr) { if (config_ext == NULL || section == NULL || addr == NULL) return FALSE; const std::string* value; char ver_list[MTK_STACK_CONFIG_NAME_VALUE_MAX] = {0}; int value_len = 0; int pattern_len = 0; uint8_t lmp_ver = 0; uint16_t mfct_set = 0; uint16_t lmp_subver = 0; uint8_t state = MTK_STACK_CONFIG_VERSION; char pattern[13] = {0}; char buffer[5]; if (!BTM_ReadRemoteVersion(*addr, &lmp_ver, &mfct_set, &lmp_subver)) { LOG(INFO) << StringPrintf("%s: %s BTM_ReadRemoteVersion", LOG_TAG, __func__); return FALSE; } if (0 == lmp_ver && 0 == mfct_set && 0 == lmp_subver) { LOG(INFO) << StringPrintf("%s: %s get remote version fail", LOG_TAG, __func__); return FALSE; } if (interop_mtk_match_ver_byconfig(*config_org, section, state, lmp_ver, mfct_set, lmp_subver)) return TRUE; if (interop_mtk_match_ver_byconfig(*config_ext, section, state, lmp_ver, mfct_set, lmp_subver)) return TRUE; memset(buffer, '\0', sizeof(buffer)); if (state & MTK_STACK_CONFIG_VERSION_LMP_VER) { utoa(lmp_ver, buffer, 16, 2); strcat(pattern, buffer); strcat(pattern, ":"); memset(buffer, '\0', sizeof(buffer)); } if (state & MTK_STACK_CONFIG_VERSION_MFCT) { utoa(mfct_set, buffer, 16, 4); strcat(pattern, buffer); strcat(pattern, ":"); memset(buffer, '\0', sizeof(buffer)); } if (state & MTK_STACK_CONFIG_VERSION_LMP_SUBVER) { utoa(lmp_subver, buffer, 16, 4); strcat(pattern, buffer); } if ((value = get_blacklist_content(*config_ext, section, BLACKLIST_VERSION_KEY)) != NULL) { VLOG(2) << StringPrintf("%s:[%s] check %s in %s", __func__, section, pattern, value->c_str()); if (value->length() < MTK_STACK_CONFIG_NAME_VALUE_MAX) value_len = value->length(); else value_len = MTK_STACK_CONFIG_NAME_VALUE_MAX - 1; strncpy(ver_list, value->c_str(), value_len); pattern_len = strlen(pattern); if ((MTK_STACK_CONFIG_NAME_VALUE_MAX - value_len) < pattern_len + 1) { LOG(INFO) << StringPrintf("%s:[%s][size:%d] %s[len:%d] too long", __func__, section, value_len, pattern, pattern_len); return FALSE; } ver_list[value_len] = ','; strcpy(ver_list + value_len + 1, pattern); set_blacklist_content(section, BLACKLIST_VERSION_KEY, ver_list); return TRUE; } else { strncpy(ver_list, pattern, strlen(pattern)); set_blacklist_content(section, BLACKLIST_VERSION_KEY, ver_list); return TRUE; } } /**@}*/ #endif /** M: New feature: framework get black list information {@ */ bool interop_mtk_match_addr_fwk(const char* section, const RawAddress* addr) { #if defined (MTK_INTEROP_EXTENSION) && (MTK_INTEROP_EXTENSION == TRUE) return interop_mtk_match_addr_name(section, addr); #else return false; #endif } bool interop_mtk_match_name_fwk(const char* section, const char* name) { #if defined (MTK_INTEROP_EXTENSION) && (MTK_INTEROP_EXTENSION == TRUE) return interop_mtk_match_name(section, name); #else return false; #endif } bool interop_mtk_match_addr_name_fwk(const char* section, const RawAddress* addr) { #if defined (MTK_INTEROP_EXTENSION) && (MTK_INTEROP_EXTENSION == TRUE) return interop_mtk_match_addr_name(section, addr); #else return false; #endif } bool interop_mtk_match_lmp_ver_fwk(const char* section, const RawAddress* addr) { #if defined (MTK_INTEROP_EXTENSION) && (MTK_INTEROP_EXTENSION == TRUE) return interop_mtk_match_lmp_ver(section, addr); #else return false; #endif } bool interop_mtk_match_mfct_fwk(const char* section, const RawAddress* addr) { #if defined (MTK_INTEROP_EXTENSION) && (MTK_INTEROP_EXTENSION == TRUE) return interop_mtk_match_mfct(section, addr); #else return false; #endif } bool interop_mtk_match_lmp_subver_fwk(const char* section, const RawAddress* addr) { #if defined (MTK_INTEROP_EXTENSION) && (MTK_INTEROP_EXTENSION == TRUE) return interop_mtk_match_lmp_subver(section, addr); #else return false; #endif } bool interop_mtk_match_ver_fwk(const char* section, const RawAddress* addr) { #if defined (MTK_INTEROP_EXTENSION) && (MTK_INTEROP_EXTENSION == TRUE) return interop_mtk_match_ver(section, addr); #else return false; #endif } static const btinterop_mtk_interface_t interop_if = { sizeof(btinterop_mtk_interface_t), interop_mtk_match_addr_fwk, interop_mtk_match_name_fwk, interop_mtk_match_addr_name_fwk, interop_mtk_match_lmp_ver_fwk, interop_mtk_match_mfct_fwk, interop_mtk_match_lmp_subver_fwk, interop_mtk_match_ver_fwk}; const btinterop_mtk_interface_t* btif_interop_mtk_get_interface() { return &interop_if; } /**@}*/ #endif