/****************************************************************************** * * Copyright (C) 2014 Broadcom Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ******************************************************************************/ //#define LOG_TAG "bt_btm_ble" #include #include "common/bt_target.h" #if (BLE_INCLUDED == TRUE) #include "stack/bt_types.h" #include "stack/hcimsgs.h" #include "stack/btu.h" #include "btm_int.h" #include "osi/allocator.h" #include "stack/hcidefs.h" #include "stack/btm_ble_api.h" #include "device/controller.h" #define BTM_BLE_ADV_FILT_META_HDR_LENGTH 3 #define BTM_BLE_ADV_FILT_FEAT_SELN_LEN 13 #define BTM_BLE_ADV_FILT_TRACK_NUM 2 #define BTM_BLE_PF_SELECT_NONE 0 /* BLE meta vsc header: 1 bytes of sub_code, 1 byte of PCF action */ #define BTM_BLE_META_HDR_LENGTH 3 #define BTM_BLE_PF_FEAT_SEL_LEN 18 #define BTM_BLE_PCF_ENABLE_LEN 2 #define BTM_BLE_META_ADDR_LEN 7 #define BTM_BLE_META_UUID_LEN 40 #define BTM_BLE_PF_BIT_TO_MASK(x) (UINT16)(1 << (x)) tBTM_BLE_ADV_FILTER_CB btm_ble_adv_filt_cb; tBTM_BLE_VSC_CB cmn_ble_vsc_cb; static const BD_ADDR na_bda = {0}; static UINT8 btm_ble_cs_update_pf_counter(tBTM_BLE_SCAN_COND_OP action, UINT8 cond_type, tBLE_BD_ADDR *p_bd_addr, UINT8 num_available); #define BTM_BLE_SET_SCAN_PF_OPCODE(x, y) (((x)<<4)|y) #define BTM_BLE_GET_SCAN_PF_SUBCODE(x) ((x) >> 4) #define BTM_BLE_GET_SCAN_PF_ACTION(x) ((x) & 0x0f) #define BTM_BLE_INVALID_COUNTER 0xff /* length of each multi adv sub command */ #define BTM_BLE_ADV_FILTER_ENB_LEN 3 /* length of each batch scan command */ #define BTM_BLE_ADV_FILTER_CLEAR_LEN 3 #define BTM_BLE_ADV_FILTER_LEN 2 #define BTM_BLE_ADV_FILT_CB_EVT_MASK 0xF0 #define BTM_BLE_ADV_FILT_SUBCODE_MASK 0x0F /******************************************************************************* ** ** Function btm_ble_obtain_vsc_details ** ** Description This function obtains the VSC details ** ** Parameters ** ** Returns status ** *******************************************************************************/ tBTM_STATUS btm_ble_obtain_vsc_details() { tBTM_STATUS st = BTM_SUCCESS; #if BLE_VND_INCLUDED == TRUE BTM_BleGetVendorCapabilities(&cmn_ble_vsc_cb); if (0 == cmn_ble_vsc_cb.max_filter) { st = BTM_MODE_UNSUPPORTED; return st; } #else cmn_ble_vsc_cb.max_filter = BTM_BLE_MAX_FILTER_COUNTER; #endif return st; } /******************************************************************************* ** ** Function btm_ble_advfilt_enq_op_q ** ** Description enqueue an adv filter operation in q to check command complete ** status ** ** Returns void ** *******************************************************************************/ void btm_ble_advfilt_enq_op_q(UINT8 action, UINT8 ocf, tBTM_BLE_FILT_CB_EVT cb_evt, tBTM_BLE_REF_VALUE ref, tBTM_BLE_PF_CFG_CBACK *p_cmpl_cback, tBTM_BLE_PF_PARAM_CBACK *p_filt_param_cback) { btm_ble_adv_filt_cb.op_q.action_ocf[btm_ble_adv_filt_cb.op_q.next_idx] = (action | (ocf << 4)); btm_ble_adv_filt_cb.op_q.ref_value[btm_ble_adv_filt_cb.op_q.next_idx] = ref; btm_ble_adv_filt_cb.op_q.cb_evt[btm_ble_adv_filt_cb.op_q.next_idx] = cb_evt; btm_ble_adv_filt_cb.op_q.p_scan_cfg_cback[btm_ble_adv_filt_cb.op_q.next_idx] = p_cmpl_cback; btm_ble_adv_filt_cb.op_q.p_filt_param_cback[btm_ble_adv_filt_cb.op_q.next_idx] = p_filt_param_cback; BTM_TRACE_DEBUG("btm_ble_advfilt_enq_op_q: act_ocf:%d, action:%d, ocf:%d,cb_evt;%d, cback:%p", btm_ble_adv_filt_cb.op_q.action_ocf[btm_ble_adv_filt_cb.op_q.next_idx], action, ocf, cb_evt, p_cmpl_cback); btm_ble_adv_filt_cb.op_q.next_idx = (btm_ble_adv_filt_cb.op_q.next_idx + 1) % BTM_BLE_PF_TYPE_MAX; } /******************************************************************************* ** ** Function btm_ble_advfilt_deq_op_q ** ** Description dequeue an adv filter operation from q when command complete ** is received ** ** Returns void ** *******************************************************************************/ void btm_ble_advfilt_deq_op_q(UINT8 *p_action, UINT8 *p_ocf, tBTM_BLE_FILT_CB_EVT *p_cb_evt, tBTM_BLE_REF_VALUE *p_ref, tBTM_BLE_PF_CFG_CBACK **p_cmpl_cback, tBTM_BLE_PF_PARAM_CBACK **p_filt_param_cback) { *p_ocf = (btm_ble_adv_filt_cb.op_q.action_ocf[btm_ble_adv_filt_cb.op_q.pending_idx] >> 4); *p_action = (btm_ble_adv_filt_cb.op_q.action_ocf[btm_ble_adv_filt_cb.op_q.pending_idx] & BTM_BLE_ADV_FILT_SUBCODE_MASK); *p_ref = btm_ble_adv_filt_cb.op_q.ref_value[btm_ble_adv_filt_cb.op_q.pending_idx]; *p_cb_evt = btm_ble_adv_filt_cb.op_q.cb_evt[btm_ble_adv_filt_cb.op_q.pending_idx]; *p_cmpl_cback = btm_ble_adv_filt_cb.op_q.p_scan_cfg_cback[btm_ble_adv_filt_cb.op_q.pending_idx]; *p_filt_param_cback = btm_ble_adv_filt_cb.op_q.p_filt_param_cback[btm_ble_adv_filt_cb.op_q.pending_idx]; btm_ble_adv_filt_cb.op_q.pending_idx = (btm_ble_adv_filt_cb.op_q.pending_idx + 1) % BTM_BLE_PF_TYPE_MAX; BTM_TRACE_DEBUG("btm_ble_advfilt_deq_op_q: ocf:%d, action:%d, ref_value:%d, cb_evt:%x", *p_ocf, *p_action, *p_ref, *p_cb_evt); } /******************************************************************************* ** ** Function btm_ble_condtype_to_ocf ** ** Description Convert cond_type to OCF ** ** Returns Returns ocf value ** *******************************************************************************/ UINT8 btm_ble_condtype_to_ocf(UINT8 cond_type) { UINT8 ocf = 0; switch (cond_type) { case BTM_BLE_PF_ADDR_FILTER: ocf = BTM_BLE_META_PF_ADDR; break; case BTM_BLE_PF_SRVC_UUID: ocf = BTM_BLE_META_PF_UUID; break; case BTM_BLE_PF_SRVC_SOL_UUID: ocf = BTM_BLE_META_PF_SOL_UUID; break; case BTM_BLE_PF_LOCAL_NAME: ocf = BTM_BLE_META_PF_LOCAL_NAME; break; case BTM_BLE_PF_MANU_DATA: ocf = BTM_BLE_META_PF_MANU_DATA; break; case BTM_BLE_PF_SRVC_DATA_PATTERN: ocf = BTM_BLE_META_PF_SRVC_DATA; break; case BTM_BLE_PF_TYPE_ALL: ocf = BTM_BLE_META_PF_ALL; break; default: ocf = BTM_BLE_PF_TYPE_MAX; break; } return ocf; } /******************************************************************************* ** ** Function btm_ble_ocf_to_condtype ** ** Description Convert OCF to cond type ** ** Returns Returns condtype value ** *******************************************************************************/ UINT8 btm_ble_ocf_to_condtype(UINT8 ocf) { UINT8 cond_type = 0; switch (ocf) { case BTM_BLE_META_PF_FEAT_SEL: cond_type = BTM_BLE_META_PF_FEAT_SEL; break; case BTM_BLE_META_PF_ADDR: cond_type = BTM_BLE_PF_ADDR_FILTER; break; case BTM_BLE_META_PF_UUID: cond_type = BTM_BLE_PF_SRVC_UUID; break; case BTM_BLE_META_PF_SOL_UUID: cond_type = BTM_BLE_PF_SRVC_SOL_UUID; break; case BTM_BLE_META_PF_LOCAL_NAME: cond_type = BTM_BLE_PF_LOCAL_NAME; break; case BTM_BLE_META_PF_MANU_DATA: cond_type = BTM_BLE_PF_MANU_DATA; break; case BTM_BLE_META_PF_SRVC_DATA: cond_type = BTM_BLE_PF_SRVC_DATA_PATTERN; break; case BTM_BLE_META_PF_ALL: cond_type = BTM_BLE_PF_TYPE_ALL; break; default: cond_type = BTM_BLE_PF_TYPE_MAX; break; } return cond_type; } /******************************************************************************* ** ** Function btm_ble_scan_pf_cmpl_cback ** ** Description the BTM BLE customer feature VSC complete callback for ADV PF filtering ** ** Returns pointer to the counter if found; NULL otherwise. ** *******************************************************************************/ void btm_ble_scan_pf_cmpl_cback(tBTM_VSC_CMPL *p_params) { UINT8 status = 0; UINT8 *p = p_params->p_param_buf, op_subcode = 0, action = 0xff; UINT16 evt_len = p_params->param_len; UINT8 ocf = BTM_BLE_META_PF_ALL, cond_type = 0; UINT8 num_avail = 0, cb_evt = 0; tBTM_BLE_REF_VALUE ref_value = 0; tBTM_BLE_PF_CFG_CBACK *p_scan_cfg_cback = NULL; tBTM_BLE_PF_PARAM_CBACK *p_filt_param_cback = NULL; if (evt_len < 3 || evt_len > 4) { BTM_TRACE_ERROR("%s cannot interpret APCF callback status = %d, length = %d", __func__, status, evt_len); btm_ble_advfilt_deq_op_q(&action, &ocf, &cb_evt, &ref_value, &p_scan_cfg_cback, &p_filt_param_cback); return; } btm_ble_advfilt_deq_op_q(&action, &ocf, &cb_evt, &ref_value, &p_scan_cfg_cback, &p_filt_param_cback); STREAM_TO_UINT8(status, p); STREAM_TO_UINT8(op_subcode, p); STREAM_TO_UINT8(action, p); /* Ignore the event, if it is not the same one expected */ if (3 == evt_len) { if (ocf != op_subcode) { BTM_TRACE_ERROR("btm_ble_scan_pf_cmpl_cback:3-Incorrect opcode :%d, %d, %d, %d, %d, %d", ocf, op_subcode, action, evt_len, ref_value, status); return; } else { if (NULL != btm_ble_adv_filt_cb.p_filt_stat_cback) { btm_ble_adv_filt_cb.p_filt_stat_cback(action, status, ref_value); } BTM_TRACE_DEBUG("btm_ble_scan_pf_cmpl_cback enabled/disabled, %d, %d, %d, %d", ocf, action, status, ref_value); return; } } if (4 == evt_len && ocf != op_subcode) { BTM_TRACE_ERROR("btm_ble_scan_pf_cmpl_cback:4-Incorrect opcode: %d, %d, %d, %d, %d", ocf, op_subcode, action, status, ref_value); return; } STREAM_TO_UINT8(num_avail, p); switch (op_subcode) { case BTM_BLE_META_PF_ADDR: case BTM_BLE_META_PF_UUID: case BTM_BLE_META_PF_SOL_UUID: case BTM_BLE_META_PF_LOCAL_NAME: case BTM_BLE_META_PF_MANU_DATA: case BTM_BLE_META_PF_SRVC_DATA: cond_type = btm_ble_ocf_to_condtype(ocf); BTM_TRACE_DEBUG("btm_ble_scan_pf_cmpl_cback Recd: %d, %d, %d, %d, %d, %d", op_subcode, ocf, action, status, ref_value, num_avail); if (HCI_SUCCESS == status) { if (memcmp(&btm_ble_adv_filt_cb.cur_filter_target.bda, &na_bda, BD_ADDR_LEN) == 0) { btm_ble_cs_update_pf_counter(action, cond_type, NULL, num_avail); } else { btm_ble_cs_update_pf_counter(action, cond_type, &btm_ble_adv_filt_cb.cur_filter_target, num_avail); } } /* send ADV PF operation complete */ btm_ble_adv_filt_cb.op_type = 0; break; case BTM_BLE_META_PF_FEAT_SEL: BTM_TRACE_DEBUG("btm_ble_scan_pf_cmpl_cback-Feat sel event: %d, %d, %d, %d", action, status, ref_value, num_avail); break; default: BTM_TRACE_ERROR("btm_ble_scan_pf_cmpl_cback: unknown operation: %d", op_subcode); break; } BTM_TRACE_DEBUG("btm_ble_scan_pf_cmpl_cback: calling the cback: %d", cb_evt); switch (cb_evt) { case BTM_BLE_FILT_CFG: if (NULL != p_scan_cfg_cback) { p_scan_cfg_cback(action, cond_type, num_avail, status, ref_value); } break; case BTM_BLE_FILT_ADV_PARAM: if (NULL != p_filt_param_cback) { p_filt_param_cback(action, num_avail, ref_value, status); } break; default: break; } } /******************************************************************************* ** ** Function btm_ble_find_addr_filter_counter ** ** Description find the per bd address ADV payload filter counter by BD_ADDR. ** ** Returns pointer to the counter if found; NULL otherwise. ** *******************************************************************************/ tBTM_BLE_PF_COUNT *btm_ble_find_addr_filter_counter(tBLE_BD_ADDR *p_le_bda) { UINT8 i; tBTM_BLE_PF_COUNT *p_addr_filter = &btm_ble_adv_filt_cb.p_addr_filter_count[1]; if (p_le_bda == NULL) { return &btm_ble_adv_filt_cb.p_addr_filter_count[0]; } for (i = 0; i < cmn_ble_vsc_cb.max_filter; i ++, p_addr_filter ++) { if (p_addr_filter->in_use && memcmp(p_le_bda->bda, p_addr_filter->bd_addr, BD_ADDR_LEN) == 0) { return p_addr_filter; } } return NULL; } /******************************************************************************* ** ** Function btm_ble_alloc_addr_filter_counter ** ** Description allocate the per device adv payload filter counter. ** ** Returns pointer to the counter if allocation succeed; NULL otherwise. ** *******************************************************************************/ tBTM_BLE_PF_COUNT *btm_ble_alloc_addr_filter_counter(BD_ADDR bd_addr) { UINT8 i; tBTM_BLE_PF_COUNT *p_addr_filter = &btm_ble_adv_filt_cb.p_addr_filter_count[1]; for (i = 0; i < cmn_ble_vsc_cb.max_filter; i ++, p_addr_filter ++) { if (memcmp(na_bda, p_addr_filter->bd_addr, BD_ADDR_LEN) == 0) { memcpy(p_addr_filter->bd_addr, bd_addr, BD_ADDR_LEN); p_addr_filter->in_use = TRUE; return p_addr_filter; } } return NULL; } /******************************************************************************* ** ** Function btm_ble_dealloc_addr_filter_counter ** ** Description de-allocate the per device adv payload filter counter. ** ** Returns TRUE if deallocation succeed; FALSE otherwise. ** *******************************************************************************/ BOOLEAN btm_ble_dealloc_addr_filter_counter(tBLE_BD_ADDR *p_bd_addr, UINT8 filter_type) { UINT8 i; tBTM_BLE_PF_COUNT *p_addr_filter = &btm_ble_adv_filt_cb.p_addr_filter_count[1]; BOOLEAN found = FALSE; if (BTM_BLE_PF_TYPE_ALL == filter_type && NULL == p_bd_addr) { memset(&btm_ble_adv_filt_cb.p_addr_filter_count[0], 0, sizeof(tBTM_BLE_PF_COUNT)); } for (i = 0; i < cmn_ble_vsc_cb.max_filter; i ++, p_addr_filter ++) { if ((p_addr_filter->in_use) && (NULL == p_bd_addr || (NULL != p_bd_addr && memcmp(p_bd_addr->bda, p_addr_filter->bd_addr, BD_ADDR_LEN) == 0))) { found = TRUE; memset(p_addr_filter, 0, sizeof(tBTM_BLE_PF_COUNT)); if (NULL != p_bd_addr) { break; } } } return found; } /******************************************************************************* ** ** Function btm_ble_update_pf_local_name ** ** Description this function update(add,delete or clear) the adv lcoal name filtering condition. ** ** ** Returns BTM_SUCCESS if sucessful, ** BTM_ILLEGAL_VALUE if paramter is not valid. ** *******************************************************************************/ tBTM_STATUS btm_ble_update_pf_local_name(tBTM_BLE_SCAN_COND_OP action, tBTM_BLE_PF_FILT_INDEX filt_index, tBTM_BLE_PF_COND_PARAM *p_cond) { tBTM_BLE_PF_LOCAL_NAME_COND *p_local_name = (p_cond == NULL) ? NULL : &p_cond->local_name; UINT8 param[BTM_BLE_PF_STR_LEN_MAX + BTM_BLE_ADV_FILT_META_HDR_LENGTH], *p = param, len = BTM_BLE_ADV_FILT_META_HDR_LENGTH; tBTM_STATUS st = BTM_ILLEGAL_VALUE; memset(param, 0, BTM_BLE_PF_STR_LEN_MAX + BTM_BLE_ADV_FILT_META_HDR_LENGTH); UINT8_TO_STREAM(p, BTM_BLE_META_PF_LOCAL_NAME); UINT8_TO_STREAM(p, action); /* Filter index */ UINT8_TO_STREAM(p, filt_index); if (BTM_BLE_SCAN_COND_ADD == action || BTM_BLE_SCAN_COND_DELETE == action) { if (NULL == p_local_name) { return st; } if (p_local_name->data_len > BTM_BLE_PF_STR_LEN_MAX) { p_local_name->data_len = BTM_BLE_PF_STR_LEN_MAX; } ARRAY_TO_STREAM(p, p_local_name->p_data, p_local_name->data_len); len += p_local_name->data_len; } /* send local name filter */ if ((st = BTM_VendorSpecificCommand (HCI_BLE_ADV_FILTER_OCF, len, param, btm_ble_scan_pf_cmpl_cback)) != BTM_NO_RESOURCES) { memset(&btm_ble_adv_filt_cb.cur_filter_target, 0, sizeof(tBLE_BD_ADDR)); } else { BTM_TRACE_ERROR("Local Name PF filter update failed"); } return st; } /******************************************************************************* ** ** Function btm_ble_update_srvc_data_change ** ** Description this function update(add/remove) service data change filter. ** ** ** Returns BTM_SUCCESS if sucessful, ** BTM_ILLEGAL_VALUE if paramter is not valid. ** *******************************************************************************/ tBTM_STATUS btm_ble_update_srvc_data_change(tBTM_BLE_SCAN_COND_OP action, tBTM_BLE_PF_FILT_INDEX filt_index, tBTM_BLE_PF_COND_PARAM *p_cond) { tBTM_STATUS st = BTM_ILLEGAL_VALUE; tBLE_BD_ADDR *p_bd_addr = p_cond ? &p_cond->target_addr : NULL; UINT8 num_avail = (action == BTM_BLE_SCAN_COND_ADD) ? 0 : 1; if (btm_ble_cs_update_pf_counter (action, BTM_BLE_PF_SRVC_DATA, p_bd_addr, num_avail) != BTM_BLE_INVALID_COUNTER) { st = BTM_SUCCESS; } return st; } /******************************************************************************* ** ** Function btm_ble_update_pf_manu_data ** ** Description this function update(add,delete or clear) the adv manufacturer ** data filtering condition. ** ** ** Returns BTM_SUCCESS if sucessful, ** BTM_ILLEGAL_VALUE if paramter is not valid. ** *******************************************************************************/ tBTM_STATUS btm_ble_update_pf_manu_data(tBTM_BLE_SCAN_COND_OP action, tBTM_BLE_PF_FILT_INDEX filt_index, tBTM_BLE_PF_COND_PARAM *p_data, tBTM_BLE_PF_COND_TYPE cond_type, tBTM_BLE_FILT_CB_EVT cb_evt, tBTM_BLE_REF_VALUE ref_value) { tBTM_BLE_PF_MANU_COND *p_manu_data = (p_data == NULL) ? NULL : &p_data->manu_data; tBTM_BLE_PF_SRVC_PATTERN_COND *p_srvc_data = (p_data == NULL) ? NULL : &p_data->srvc_data; UINT8 param[BTM_BLE_PF_STR_LEN_MAX + BTM_BLE_PF_STR_LEN_MAX + BTM_BLE_ADV_FILT_META_HDR_LENGTH], *p = param, len = BTM_BLE_ADV_FILT_META_HDR_LENGTH; tBTM_STATUS st = BTM_ILLEGAL_VALUE; if (NULL == p_data) { return st; } memset(param, 0, BTM_BLE_PF_STR_LEN_MAX + BTM_BLE_PF_STR_LEN_MAX + BTM_BLE_ADV_FILT_META_HDR_LENGTH); if (BTM_BLE_PF_SRVC_DATA_PATTERN == cond_type) { UINT8_TO_STREAM(p, BTM_BLE_META_PF_SRVC_DATA); } else { UINT8_TO_STREAM(p, BTM_BLE_META_PF_MANU_DATA); } UINT8_TO_STREAM(p, action); /* Filter index */ UINT8_TO_STREAM(p, filt_index); if (BTM_BLE_SCAN_COND_ADD == action || BTM_BLE_SCAN_COND_DELETE == action) { if (BTM_BLE_PF_SRVC_DATA_PATTERN == cond_type) { if (NULL == p_srvc_data) { return st; } if (p_srvc_data->data_len > (BTM_BLE_PF_STR_LEN_MAX - 2)) { p_srvc_data->data_len = (BTM_BLE_PF_STR_LEN_MAX - 2); } if (p_srvc_data->data_len > 0) { ARRAY_TO_STREAM(p, p_srvc_data->p_pattern, p_srvc_data->data_len); len += (p_srvc_data->data_len); ARRAY_TO_STREAM(p, p_srvc_data->p_pattern_mask, p_srvc_data->data_len); } len += (p_srvc_data->data_len); BTM_TRACE_DEBUG("Service data length: %d", len); } else { if (NULL == p_manu_data) { BTM_TRACE_ERROR("btm_ble_update_pf_manu_data - No manuf data"); return st; } BTM_TRACE_EVENT("btm_ble_update_pf_manu_data length: %d", p_manu_data->data_len); if (p_manu_data->data_len > (BTM_BLE_PF_STR_LEN_MAX - 2)) { p_manu_data->data_len = (BTM_BLE_PF_STR_LEN_MAX - 2); } UINT16_TO_STREAM(p, p_manu_data->company_id); if (p_manu_data->data_len > 0 && p_manu_data->p_pattern_mask != NULL) { ARRAY_TO_STREAM(p, p_manu_data->p_pattern, p_manu_data->data_len); len += (p_manu_data->data_len + 2); } else { len += 2; } if (p_manu_data->company_id_mask != 0) { UINT16_TO_STREAM (p, p_manu_data->company_id_mask); } else { memset(p, 0xff, 2); p += 2; } len += 2; if (p_manu_data->data_len > 0 && p_manu_data->p_pattern_mask != NULL) { ARRAY_TO_STREAM(p, p_manu_data->p_pattern_mask, p_manu_data->data_len); len += (p_manu_data->data_len); } BTM_TRACE_DEBUG("Manuf data length: %d", len); } } /* send manufacturer*/ if ((st = BTM_VendorSpecificCommand (HCI_BLE_ADV_FILTER_OCF, len, param, btm_ble_scan_pf_cmpl_cback)) != BTM_NO_RESOURCES) { memset(&btm_ble_adv_filt_cb.cur_filter_target, 0, sizeof(tBLE_BD_ADDR)); } else { BTM_TRACE_ERROR("manufacturer data PF filter update failed"); } return st; } /******************************************************************************* ** ** Function btm_ble_cs_update_pf_counter ** ** Description this function is to update the adv data payload filter counter ** ** Returns current number of the counter; BTM_BLE_INVALID_COUNTER if ** counter update failed. ** *******************************************************************************/ UINT8 btm_ble_cs_update_pf_counter(tBTM_BLE_SCAN_COND_OP action, UINT8 cond_type, tBLE_BD_ADDR *p_bd_addr, UINT8 num_available) { tBTM_BLE_PF_COUNT *p_addr_filter = NULL; UINT8 *p_counter = NULL; btm_ble_obtain_vsc_details(); if (cond_type > BTM_BLE_PF_TYPE_ALL) { BTM_TRACE_ERROR("unknown PF filter condition type %d", cond_type); return BTM_BLE_INVALID_COUNTER; } /* for these three types of filter, always generic */ if (BTM_BLE_PF_ADDR_FILTER == cond_type || BTM_BLE_PF_MANU_DATA == cond_type || BTM_BLE_PF_LOCAL_NAME == cond_type || BTM_BLE_PF_SRVC_DATA_PATTERN == cond_type) { p_bd_addr = NULL; } if ((p_addr_filter = btm_ble_find_addr_filter_counter(p_bd_addr)) == NULL && BTM_BLE_SCAN_COND_ADD == action) { p_addr_filter = btm_ble_alloc_addr_filter_counter(p_bd_addr->bda); } if (NULL != p_addr_filter) { /* all filter just cleared */ if ((BTM_BLE_PF_TYPE_ALL == cond_type && BTM_BLE_SCAN_COND_CLEAR == action) || /* or bd address filter been deleted */ (BTM_BLE_PF_ADDR_FILTER == cond_type && (BTM_BLE_SCAN_COND_DELETE == action || BTM_BLE_SCAN_COND_CLEAR == action))) { btm_ble_dealloc_addr_filter_counter(p_bd_addr, cond_type); } /* if not feature selection, update new addition/reduction of the filter counter */ else if (cond_type != BTM_BLE_PF_TYPE_ALL) { p_counter = p_addr_filter->pf_counter; if (num_available > 0) { p_counter[cond_type] += 1; } BTM_TRACE_DEBUG("counter = %d, maxfilt = %d, num_avbl=%d", p_counter[cond_type], cmn_ble_vsc_cb.max_filter, num_available); return p_counter[cond_type]; } } else { BTM_TRACE_ERROR("no matching filter counter found"); } /* no matching filter located and updated */ return BTM_BLE_INVALID_COUNTER; } /******************************************************************************* ** ** Function btm_ble_update_addr_filter ** ** Description this function update(add,delete or clear) the address filter of adv. ** ** ** Returns BTM_SUCCESS if sucessful, ** BTM_ILLEGAL_VALUE if paramter is not valid. ** *******************************************************************************/ tBTM_STATUS btm_ble_update_addr_filter(tBTM_BLE_SCAN_COND_OP action, tBTM_BLE_PF_FILT_INDEX filt_index, tBTM_BLE_PF_COND_PARAM *p_cond) { UINT8 param[BTM_BLE_META_ADDR_LEN + BTM_BLE_ADV_FILT_META_HDR_LENGTH], * p = param; tBTM_STATUS st = BTM_ILLEGAL_VALUE; tBLE_BD_ADDR *p_addr = (p_cond == NULL) ? NULL : &p_cond->target_addr; memset(param, 0, BTM_BLE_META_ADDR_LEN + BTM_BLE_ADV_FILT_META_HDR_LENGTH); UINT8_TO_STREAM(p, BTM_BLE_META_PF_ADDR); UINT8_TO_STREAM(p, action); /* Filter index */ UINT8_TO_STREAM(p, filt_index); if (BTM_BLE_SCAN_COND_ADD == action || BTM_BLE_SCAN_COND_DELETE == action) { if (NULL == p_addr) { return st; } BDADDR_TO_STREAM(p, p_addr->bda); UINT8_TO_STREAM(p, p_addr->type); } /* send address filter */ if ((st = BTM_VendorSpecificCommand (HCI_BLE_ADV_FILTER_OCF, (UINT8)(BTM_BLE_ADV_FILT_META_HDR_LENGTH + BTM_BLE_META_ADDR_LEN), param, btm_ble_scan_pf_cmpl_cback)) != BTM_NO_RESOURCES) { memset(&btm_ble_adv_filt_cb.cur_filter_target, 0, sizeof(tBLE_BD_ADDR)); } else { BTM_TRACE_ERROR("Broadcaster Address Filter Update failed"); } return st; } /******************************************************************************* ** ** Function btm_ble_update_uuid_filter ** ** Description this function update(add,delete or clear) service UUID filter. ** ** ** Returns BTM_SUCCESS if sucessful, ** BTM_ILLEGAL_VALUE if paramter is not valid. ** *******************************************************************************/ tBTM_STATUS btm_ble_update_uuid_filter(tBTM_BLE_SCAN_COND_OP action, tBTM_BLE_PF_FILT_INDEX filt_index, tBTM_BLE_PF_COND_TYPE filter_type, tBTM_BLE_PF_COND_PARAM *p_cond, tBTM_BLE_FILT_CB_EVT cb_evt, tBTM_BLE_REF_VALUE ref_value) { UINT8 param[BTM_BLE_META_UUID_LEN + BTM_BLE_ADV_FILT_META_HDR_LENGTH], * p = param, len = BTM_BLE_ADV_FILT_META_HDR_LENGTH; tBTM_STATUS st = BTM_ILLEGAL_VALUE; tBTM_BLE_PF_UUID_COND *p_uuid_cond; UINT8 evt_type; memset(param, 0, BTM_BLE_META_UUID_LEN + BTM_BLE_ADV_FILT_META_HDR_LENGTH); if (BTM_BLE_PF_SRVC_UUID == filter_type) { evt_type = BTM_BLE_META_PF_UUID; p_uuid_cond = p_cond ? &p_cond->srvc_uuid : NULL; } else { evt_type = BTM_BLE_META_PF_SOL_UUID; p_uuid_cond = p_cond ? &p_cond->solicitate_uuid : NULL; } if (NULL == p_uuid_cond && action != BTM_BLE_SCAN_COND_CLEAR) { BTM_TRACE_ERROR("Illegal param for add/delete UUID filter"); return st; } /* need to add address filter first, if adding per bda UUID filter without address filter */ if (BTM_BLE_SCAN_COND_ADD == action && NULL != p_uuid_cond && p_uuid_cond->p_target_addr && btm_ble_find_addr_filter_counter(p_uuid_cond->p_target_addr) == NULL) { UINT8_TO_STREAM(p, BTM_BLE_META_PF_ADDR); UINT8_TO_STREAM(p, action); /* Filter index */ UINT8_TO_STREAM(p, filt_index); BDADDR_TO_STREAM(p, p_uuid_cond->p_target_addr->bda); UINT8_TO_STREAM(p, p_uuid_cond->p_target_addr->type); /* send address filter */ if ((st = BTM_VendorSpecificCommand (HCI_BLE_ADV_FILTER_OCF, (UINT8)(BTM_BLE_ADV_FILT_META_HDR_LENGTH + BTM_BLE_META_ADDR_LEN), param, btm_ble_scan_pf_cmpl_cback)) == BTM_NO_RESOURCES) { BTM_TRACE_ERROR("Update Address filter into controller failed."); return st; } btm_ble_advfilt_enq_op_q(action, BTM_BLE_META_PF_ADDR, cb_evt, ref_value, NULL, NULL); BTM_TRACE_DEBUG("Updated Address filter"); } p = param; UINT8_TO_STREAM(p, evt_type); UINT8_TO_STREAM(p, action); /* Filter index */ UINT8_TO_STREAM(p, filt_index); if ((BTM_BLE_SCAN_COND_ADD == action || BTM_BLE_SCAN_COND_DELETE == action) && NULL != p_uuid_cond) { if (p_uuid_cond->uuid.len == LEN_UUID_16) { UINT16_TO_STREAM(p, p_uuid_cond->uuid.uu.uuid16); len += LEN_UUID_16; } else if (p_uuid_cond->uuid.len == LEN_UUID_32) { /*4 bytes */ UINT32_TO_STREAM(p, p_uuid_cond->uuid.uu.uuid32); len += LEN_UUID_32; } else if (p_uuid_cond->uuid.len == LEN_UUID_128) { ARRAY_TO_STREAM (p, p_uuid_cond->uuid.uu.uuid128, LEN_UUID_128); len += LEN_UUID_128; } else { BTM_TRACE_ERROR("illegal UUID length: %d", p_uuid_cond->uuid.len); return BTM_ILLEGAL_VALUE; } if (NULL != p_uuid_cond->p_uuid_mask) { if (p_uuid_cond->uuid.len == LEN_UUID_16) { UINT16_TO_STREAM(p, p_uuid_cond->p_uuid_mask->uuid16_mask); len += LEN_UUID_16; } else if (p_uuid_cond->uuid.len == LEN_UUID_32) { /*4 bytes */ UINT32_TO_STREAM(p, p_uuid_cond->p_uuid_mask->uuid32_mask); len += LEN_UUID_32; } else if (p_uuid_cond->uuid.len == LEN_UUID_128) { ARRAY_TO_STREAM (p, p_uuid_cond->p_uuid_mask->uuid128_mask, LEN_UUID_128); len += LEN_UUID_128; } } else { memset(p, 0xff, p_uuid_cond->uuid.len); len += p_uuid_cond->uuid.len; } BTM_TRACE_DEBUG("btm_ble_update_uuid_filter : %d, %d, %d, %d", filter_type, evt_type, p_uuid_cond->uuid.len, len); } /* send UUID filter update */ if ((st = BTM_VendorSpecificCommand (HCI_BLE_ADV_FILTER_OCF, len, param, btm_ble_scan_pf_cmpl_cback)) != BTM_NO_RESOURCES) { if (p_uuid_cond && p_uuid_cond->p_target_addr) { memcpy(&btm_ble_adv_filt_cb.cur_filter_target, p_uuid_cond->p_target_addr, sizeof(tBLE_BD_ADDR)); } else { memset(&btm_ble_adv_filt_cb.cur_filter_target, 0, sizeof(tBLE_BD_ADDR)); } } else { BTM_TRACE_ERROR("UUID filter udpating failed"); } return st; } /******************************************************************************* ** ** Function btm_ble_clear_scan_pf_filter ** ** Description clear all adv payload filter by de-select all the adv pf feature bits ** ** ** Returns BTM_SUCCESS if sucessful, ** BTM_ILLEGAL_VALUE if paramter is not valid. ** *******************************************************************************/ tBTM_STATUS btm_ble_clear_scan_pf_filter(tBTM_BLE_SCAN_COND_OP action, tBTM_BLE_PF_FILT_INDEX filt_index, tBTM_BLE_PF_COND_PARAM *p_cond, tBTM_BLE_PF_CFG_CBACK *p_cmpl_cback, tBTM_BLE_FILT_CB_EVT cb_evt, tBTM_BLE_REF_VALUE ref_value) { tBLE_BD_ADDR *p_target = (p_cond == NULL) ? NULL : &p_cond->target_addr; tBTM_BLE_PF_COUNT *p_bda_filter; tBTM_STATUS st = BTM_WRONG_MODE; UINT8 param[20], *p; if (BTM_BLE_SCAN_COND_CLEAR != action) { BTM_TRACE_ERROR("unable to perform action:%d for generic adv filter type", action); return BTM_ILLEGAL_VALUE; } p = param; memset(param, 0, 20); p_bda_filter = btm_ble_find_addr_filter_counter(p_target); if (NULL == p_bda_filter || /* not a generic filter */ (p_target != NULL && p_bda_filter)) { BTM_TRACE_ERROR("Error: Can not clear filter, No PF filter has been configured!"); return st; } /* clear the general filter entry */ if (NULL == p_target) { /* clear manufacturer data filter */ st = btm_ble_update_pf_manu_data(BTM_BLE_SCAN_COND_CLEAR, filt_index, NULL, BTM_BLE_PF_MANU_DATA, cb_evt, ref_value); if (BTM_CMD_STARTED == st) { btm_ble_advfilt_enq_op_q(action, BTM_BLE_META_PF_MANU_DATA, cb_evt, ref_value, NULL, NULL); } /* clear local name filter */ st = btm_ble_update_pf_local_name(BTM_BLE_SCAN_COND_CLEAR, filt_index, NULL); if (BTM_CMD_STARTED == st) { btm_ble_advfilt_enq_op_q(action, BTM_BLE_META_PF_LOCAL_NAME, cb_evt, ref_value, NULL, NULL); } /* update the counter for service data */ st = btm_ble_update_srvc_data_change(BTM_BLE_SCAN_COND_CLEAR, filt_index, NULL); /* clear UUID filter */ st = btm_ble_update_uuid_filter(BTM_BLE_SCAN_COND_CLEAR, filt_index, BTM_BLE_PF_SRVC_UUID, NULL, cb_evt, ref_value); if (BTM_CMD_STARTED == st) { btm_ble_advfilt_enq_op_q(action, BTM_BLE_META_PF_UUID, cb_evt, ref_value, NULL, NULL); } st = btm_ble_update_uuid_filter(BTM_BLE_SCAN_COND_CLEAR, filt_index, BTM_BLE_PF_SRVC_SOL_UUID, NULL, cb_evt, ref_value); if (BTM_CMD_STARTED == st) { btm_ble_advfilt_enq_op_q(action, BTM_BLE_META_PF_SOL_UUID, cb_evt, ref_value, NULL, NULL); } /* clear service data filter */ st = btm_ble_update_pf_manu_data(BTM_BLE_SCAN_COND_CLEAR, filt_index, NULL, BTM_BLE_PF_SRVC_DATA_PATTERN, cb_evt, ref_value); if (BTM_CMD_STARTED == st) { btm_ble_advfilt_enq_op_q(action, BTM_BLE_META_PF_SRVC_DATA, cb_evt, ref_value, NULL, NULL); } } /* select feature based on control block settings */ UINT8_TO_STREAM(p, BTM_BLE_META_PF_FEAT_SEL); UINT8_TO_STREAM(p, BTM_BLE_SCAN_COND_CLEAR); /* Filter index */ UINT8_TO_STREAM(p, filt_index); /* set PCF selection */ UINT32_TO_STREAM(p, BTM_BLE_PF_SELECT_NONE); /* set logic condition as OR as default */ UINT8_TO_STREAM(p, BTM_BLE_PF_LOGIC_OR); if ((st = BTM_VendorSpecificCommand (HCI_BLE_ADV_FILTER_OCF, (UINT8)(BTM_BLE_ADV_FILT_META_HDR_LENGTH + BTM_BLE_PF_FEAT_SEL_LEN), param, btm_ble_scan_pf_cmpl_cback)) != BTM_NO_RESOURCES) { if (p_target) { memcpy(&btm_ble_adv_filt_cb.cur_filter_target, p_target, sizeof(tBLE_BD_ADDR)); } else { memset(&btm_ble_adv_filt_cb.cur_filter_target, 0, sizeof(tBLE_BD_ADDR)); } } return st; } /******************************************************************************* ** ** Function BTM_BleAdvFilterParamSetup ** ** Description This function is called to setup the adv data payload filter ** condition. ** ** Parameters action - Type of action to be performed ** filt_index - Filter index ** p_filt_params - Filter parameters ** p_target - Target device ** p_cmpl_back - Callback pointer ** ref_value - reference value ** ** Returns void ** *******************************************************************************/ tBTM_STATUS BTM_BleAdvFilterParamSetup(int action, tBTM_BLE_PF_FILT_INDEX filt_index, tBTM_BLE_PF_FILT_PARAMS *p_filt_params, tBLE_BD_ADDR *p_target, tBTM_BLE_PF_PARAM_CBACK *p_cmpl_cback, tBTM_BLE_REF_VALUE ref_value) { tBTM_STATUS st = BTM_WRONG_MODE; tBTM_BLE_PF_COUNT *p_bda_filter = NULL; UINT8 len = BTM_BLE_ADV_FILT_META_HDR_LENGTH + BTM_BLE_ADV_FILT_FEAT_SELN_LEN + BTM_BLE_ADV_FILT_TRACK_NUM; UINT8 param[len], *p; if (BTM_SUCCESS != btm_ble_obtain_vsc_details()) { return st; } p = param; memset(param, 0, len); BTM_TRACE_EVENT (" BTM_BleAdvFilterParamSetup"); if (BTM_BLE_SCAN_COND_ADD == action) { p_bda_filter = btm_ble_find_addr_filter_counter(p_target); if (NULL == p_bda_filter) { BTM_TRACE_ERROR("BD Address not found!"); return st; } BTM_TRACE_DEBUG("BTM_BleAdvFilterParamSetup : Feat mask:%d", p_filt_params->feat_seln); /* select feature based on control block settings */ UINT8_TO_STREAM(p, BTM_BLE_META_PF_FEAT_SEL); UINT8_TO_STREAM(p, BTM_BLE_SCAN_COND_ADD); /* Filter index */ UINT8_TO_STREAM(p, filt_index); /* set PCF selection */ UINT16_TO_STREAM(p, p_filt_params->feat_seln); /* set logic type */ UINT16_TO_STREAM(p, p_filt_params->logic_type); /* set logic condition */ UINT8_TO_STREAM(p, p_filt_params->filt_logic_type); /* set RSSI high threshold */ UINT8_TO_STREAM(p, p_filt_params->rssi_high_thres); /* set delivery mode */ UINT8_TO_STREAM(p, p_filt_params->dely_mode); if (0x01 == p_filt_params->dely_mode) { /* set onfound timeout */ UINT16_TO_STREAM(p, p_filt_params->found_timeout); /* set onfound timeout count*/ UINT8_TO_STREAM(p, p_filt_params->found_timeout_cnt); /* set RSSI low threshold */ UINT8_TO_STREAM(p, p_filt_params->rssi_low_thres); /* set onlost timeout */ UINT16_TO_STREAM(p, p_filt_params->lost_timeout); /* set num_of_track_entries for firmware greater than L-release version */ if (cmn_ble_vsc_cb.version_supported > BTM_VSC_CHIP_CAPABILITY_L_VERSION) { UINT16_TO_STREAM(p, p_filt_params->num_of_tracking_entries); } } if (cmn_ble_vsc_cb.version_supported == BTM_VSC_CHIP_CAPABILITY_L_VERSION) { len = BTM_BLE_ADV_FILT_META_HDR_LENGTH + BTM_BLE_ADV_FILT_FEAT_SELN_LEN; } else { len = BTM_BLE_ADV_FILT_META_HDR_LENGTH + BTM_BLE_ADV_FILT_FEAT_SELN_LEN + BTM_BLE_ADV_FILT_TRACK_NUM; } if ((st = BTM_VendorSpecificCommand (HCI_BLE_ADV_FILTER_OCF, (UINT8)len, param, btm_ble_scan_pf_cmpl_cback)) == BTM_NO_RESOURCES) { return st; } btm_ble_advfilt_enq_op_q(action, BTM_BLE_META_PF_FEAT_SEL, BTM_BLE_FILT_ADV_PARAM, ref_value, NULL, p_cmpl_cback); } else if (BTM_BLE_SCAN_COND_DELETE == action) { /* select feature based on control block settings */ UINT8_TO_STREAM(p, BTM_BLE_META_PF_FEAT_SEL); UINT8_TO_STREAM(p, BTM_BLE_SCAN_COND_DELETE); /* Filter index */ UINT8_TO_STREAM(p, filt_index); if ((st = BTM_VendorSpecificCommand (HCI_BLE_ADV_FILTER_OCF, (UINT8)(BTM_BLE_ADV_FILT_META_HDR_LENGTH), param, btm_ble_scan_pf_cmpl_cback)) == BTM_NO_RESOURCES) { return st; } btm_ble_advfilt_enq_op_q(action, BTM_BLE_META_PF_FEAT_SEL, BTM_BLE_FILT_ADV_PARAM, ref_value, NULL, p_cmpl_cback); } else if (BTM_BLE_SCAN_COND_CLEAR == action) { /* Deallocate all filters here */ btm_ble_dealloc_addr_filter_counter(NULL, BTM_BLE_PF_TYPE_ALL); /* select feature based on control block settings */ UINT8_TO_STREAM(p, BTM_BLE_META_PF_FEAT_SEL); UINT8_TO_STREAM(p, BTM_BLE_SCAN_COND_CLEAR); if ((st = BTM_VendorSpecificCommand (HCI_BLE_ADV_FILTER_OCF, (UINT8)(BTM_BLE_ADV_FILT_META_HDR_LENGTH - 1), param, btm_ble_scan_pf_cmpl_cback)) == BTM_NO_RESOURCES) { return st; } btm_ble_advfilt_enq_op_q(action, BTM_BLE_META_PF_FEAT_SEL, BTM_BLE_FILT_ADV_PARAM, ref_value, NULL, p_cmpl_cback); } return st; } /******************************************************************************* ** ** Function BTM_BleEnableDisableFilterFeature ** ** Description This function is called to enable / disable the APCF feature ** ** Parameters enable the generic scan condition. ** enable: enable or disable the filter condition ** p_stat_cback - Status callback pointer ** ref_value - Ref value ** Returns void ** *******************************************************************************/ tBTM_STATUS BTM_BleEnableDisableFilterFeature(UINT8 enable, tBTM_BLE_PF_STATUS_CBACK *p_stat_cback, tBTM_BLE_REF_VALUE ref_value) { UINT8 param[20], *p; tBTM_STATUS st = BTM_WRONG_MODE; if (BTM_SUCCESS != btm_ble_obtain_vsc_details()) { return st; } p = param; memset(param, 0, 20); /* enable the content filter in controller */ p = param; UINT8_TO_STREAM(p, BTM_BLE_META_PF_ENABLE); /* enable adv data payload filtering */ UINT8_TO_STREAM(p, enable); if ((st = BTM_VendorSpecificCommand (HCI_BLE_ADV_FILTER_OCF, BTM_BLE_PCF_ENABLE_LEN, param, btm_ble_scan_pf_cmpl_cback)) == BTM_CMD_STARTED) { btm_ble_adv_filt_cb.p_filt_stat_cback = p_stat_cback; btm_ble_advfilt_enq_op_q(enable, BTM_BLE_META_PF_ENABLE, BTM_BLE_FILT_ENABLE_DISABLE, ref_value, NULL, NULL); } return st; } /******************************************************************************* ** ** Function BTM_BleCfgFilterCondition ** ** Description This function is called to configure the adv data payload filter ** condition. ** ** Parameters action: to read/write/clear ** cond_type: filter condition type. ** filt_index - Filter index ** p_cond: filter condition parameter ** p_cmpl_cback - Config callback pointer ** ref_value - Reference value ** ** Returns void ** *******************************************************************************/ tBTM_STATUS BTM_BleCfgFilterCondition(tBTM_BLE_SCAN_COND_OP action, tBTM_BLE_PF_COND_TYPE cond_type, tBTM_BLE_PF_FILT_INDEX filt_index, tBTM_BLE_PF_COND_PARAM *p_cond, tBTM_BLE_PF_CFG_CBACK *p_cmpl_cback, tBTM_BLE_REF_VALUE ref_value) { tBTM_STATUS st = BTM_ILLEGAL_VALUE; UINT8 ocf = 0; BTM_TRACE_EVENT (" BTM_BleCfgFilterCondition action:%d, cond_type:%d, index:%d", action, cond_type, filt_index); if (BTM_SUCCESS != btm_ble_obtain_vsc_details()) { return st; } switch (cond_type) { /* write service data filter */ case BTM_BLE_PF_SRVC_DATA_PATTERN: /* write manufacturer data filter */ case BTM_BLE_PF_MANU_DATA: st = btm_ble_update_pf_manu_data(action, filt_index, p_cond, cond_type, 0, ref_value); break; /* write local name filter */ case BTM_BLE_PF_LOCAL_NAME: st = btm_ble_update_pf_local_name(action, filt_index, p_cond); break; /* filter on advertiser address */ case BTM_BLE_PF_ADDR_FILTER: st = btm_ble_update_addr_filter(action, filt_index, p_cond); break; /* filter on service/solicited UUID */ case BTM_BLE_PF_SRVC_UUID: case BTM_BLE_PF_SRVC_SOL_UUID: st = btm_ble_update_uuid_filter(action, filt_index, cond_type, p_cond, 0, ref_value); break; case BTM_BLE_PF_SRVC_DATA: st = btm_ble_update_srvc_data_change(action, filt_index, p_cond); break; case BTM_BLE_PF_TYPE_ALL: /* only used to clear filter */ st = btm_ble_clear_scan_pf_filter(action, filt_index, p_cond, p_cmpl_cback, 0, ref_value); break; default: BTM_TRACE_WARNING("condition type [%d] not supported currently.", cond_type); break; } if (BTM_CMD_STARTED == st && cond_type != BTM_BLE_PF_TYPE_ALL) { ocf = btm_ble_condtype_to_ocf(cond_type); btm_ble_advfilt_enq_op_q(action, ocf, BTM_BLE_FILT_CFG, ref_value, p_cmpl_cback, NULL); } else if (BTM_CMD_STARTED == st && BTM_BLE_PF_TYPE_ALL == cond_type) { btm_ble_advfilt_enq_op_q(action, BTM_BLE_META_PF_FEAT_SEL, BTM_BLE_FILT_CFG, ref_value, p_cmpl_cback, NULL); } return st; } /******************************************************************************* ** ** Function btm_ble_adv_filter_init ** ** Description This function initializes the adv filter control block ** ** Parameters ** ** Returns status ** *******************************************************************************/ void btm_ble_adv_filter_init(void) { memset(&btm_ble_adv_filt_cb, 0, sizeof(tBTM_BLE_MULTI_ADV_CB)); if (BTM_SUCCESS != btm_ble_obtain_vsc_details()) { return; } if (cmn_ble_vsc_cb.max_filter > 0) { btm_ble_adv_filt_cb.p_addr_filter_count = (tBTM_BLE_PF_COUNT *) osi_malloc( sizeof(tBTM_BLE_PF_COUNT) * cmn_ble_vsc_cb.max_filter); } } /******************************************************************************* ** ** Function btm_ble_adv_filter_cleanup ** ** Description This function de-initializes the adv filter control block ** ** Parameters ** ** Returns status ** *******************************************************************************/ void btm_ble_adv_filter_cleanup(void) { if (btm_ble_adv_filt_cb.p_addr_filter_count) { osi_free(btm_ble_adv_filt_cb.p_addr_filter_count); btm_ble_adv_filt_cb.p_addr_filter_count = NULL; } } #endif