Fork ESP-IDF's bluetooth component

i want better sbc encoding, and no cla will stop me
This commit is contained in:
jacqueline
2024-03-28 14:32:49 +11:00
parent 239e6d8950
commit ee29c25b29
1761 changed files with 737738 additions and 0 deletions
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,608 @@
/******************************************************************************
*
* Copyright (C) 1999-2012 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.
*
******************************************************************************/
/******************************************************************************
*
* This file contains functions for BLE address management.
*
******************************************************************************/
#include <string.h>
#include "stack/bt_types.h"
#include "stack/hcimsgs.h"
#include "stack/btu.h"
#include "btm_int.h"
#include "stack/gap_api.h"
#include "device/controller.h"
#if (defined BLE_INCLUDED && BLE_INCLUDED == TRUE)
#include "btm_ble_int.h"
#include "stack/smp_api.h"
/*******************************************************************************
**
** Function btm_gen_resolve_paddr_cmpl
**
** Description This is callback functioin when resolvable private address
** generation is complete.
**
** Returns void
**
*******************************************************************************/
static void btm_gen_resolve_paddr_cmpl(tSMP_ENC *p)
{
tBTM_LE_RANDOM_CB *p_cb = &btm_cb.ble_ctr_cb.addr_mgnt_cb;
BTM_TRACE_EVENT ("btm_gen_resolve_paddr_cmpl");
if (p) {
/* set hash to be LSB of rpAddress */
p_cb->private_addr[5] = p->param_buf[0];
p_cb->private_addr[4] = p->param_buf[1];
p_cb->private_addr[3] = p->param_buf[2];
/* set it to controller */
btm_ble_set_random_addr(p_cb->private_addr);
p_cb->exist_addr_bit |= BTM_BLE_GAP_ADDR_BIT_RESOLVABLE;
memcpy(p_cb->resolvale_addr, p_cb->private_addr, BD_ADDR_LEN);
if (p_cb->set_local_privacy_cback){
(*p_cb->set_local_privacy_cback)(BTM_SET_PRIVACY_SUCCESS);
p_cb->set_local_privacy_cback = NULL;
}
/* start a periodical timer to refresh random addr */
btu_stop_timer_oneshot(&p_cb->raddr_timer_ent);
#if (BTM_BLE_CONFORMANCE_TESTING == TRUE)
btu_start_timer_oneshot(&p_cb->raddr_timer_ent, BTU_TTYPE_BLE_RANDOM_ADDR,
btm_cb.ble_ctr_cb.rpa_tout);
#else
btu_start_timer_oneshot(&p_cb->raddr_timer_ent, BTU_TTYPE_BLE_RANDOM_ADDR,
BTM_BLE_PRIVATE_ADDR_INT);
#endif
} else {
/* random address set failure */
BTM_TRACE_DEBUG("set random address failed");
if (p_cb->set_local_privacy_cback){
(*p_cb->set_local_privacy_cback)(BTM_SET_PRIVACY_FAIL);
p_cb->set_local_privacy_cback = NULL;
}
}
}
/*******************************************************************************
**
** Function btm_gen_resolve_paddr_low
**
** Description This function is called when random address has generate the
** random number base for low 3 byte bd address.
**
** Returns void
**
*******************************************************************************/
void btm_gen_resolve_paddr_low(tBTM_RAND_ENC *p)
{
#if (BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE)
tBTM_LE_RANDOM_CB *p_cb = &btm_cb.ble_ctr_cb.addr_mgnt_cb;
tSMP_ENC output;
BTM_TRACE_EVENT ("btm_gen_resolve_paddr_low");
if (p) {
p->param_buf[2] &= (~BLE_RESOLVE_ADDR_MASK);
p->param_buf[2] |= BLE_RESOLVE_ADDR_MSB;
p_cb->private_addr[2] = p->param_buf[0];
p_cb->private_addr[1] = p->param_buf[1];
p_cb->private_addr[0] = p->param_buf[2];
/* encrypt with ur IRK */
if (!SMP_Encrypt(btm_cb.devcb.id_keys.irk, BT_OCTET16_LEN, p->param_buf, 3, &output)) {
btm_gen_resolve_paddr_cmpl(NULL);
} else {
btm_gen_resolve_paddr_cmpl(&output);
}
}
#endif
}
/*******************************************************************************
**
** Function btm_gen_resolvable_private_addr
**
** Description This function generate a resolvable private address.
**
** Returns void
**
*******************************************************************************/
void btm_gen_resolvable_private_addr (void *p_cmd_cplt_cback)
{
BTM_TRACE_EVENT ("btm_gen_resolvable_private_addr");
/* generate 3B rand as BD LSB, SRK with it, get BD MSB */
if (!btsnd_hcic_ble_rand((void *)p_cmd_cplt_cback)) {
btm_gen_resolve_paddr_cmpl(NULL);
}
}
/*******************************************************************************
**
** Function btm_gen_non_resolve_paddr_cmpl
**
** Description This is the callback function when non-resolvable private
** function is generated and write to controller.
**
** Returns void
**
*******************************************************************************/
static void btm_gen_non_resolve_paddr_cmpl(tBTM_RAND_ENC *p)
{
tBTM_LE_RANDOM_CB *p_cb = &btm_cb.ble_ctr_cb.addr_mgnt_cb;
tBTM_BLE_ADDR_CBACK *p_cback = p_cb->p_generate_cback;
void *p_data = p_cb->p;
UINT8 *pp;
BD_ADDR static_random;
BTM_TRACE_EVENT ("btm_gen_non_resolve_paddr_cmpl");
p_cb->p_generate_cback = NULL;
if (p) {
pp = p->param_buf;
STREAM_TO_BDADDR(static_random, pp);
/* mask off the 2 MSB */
static_random[0] &= BLE_STATIC_PRIVATE_MSB_MASK;
/* report complete */
if (p_cback) {
(* p_cback)(static_random, p_data);
}
} else {
BTM_TRACE_DEBUG("btm_gen_non_resolvable_private_addr failed");
if (p_cback) {
(* p_cback)(NULL, p_data);
}
}
}
/*******************************************************************************
**
** Function btm_gen_non_resolvable_private_addr
**
** Description This function generate a non-resolvable private address.
**
**
** Returns void
**
*******************************************************************************/
void btm_gen_non_resolvable_private_addr (tBTM_BLE_ADDR_CBACK *p_cback, void *p)
{
tBTM_LE_RANDOM_CB *p_mgnt_cb = &btm_cb.ble_ctr_cb.addr_mgnt_cb;
BTM_TRACE_EVENT ("btm_gen_non_resolvable_private_addr");
if (p_mgnt_cb->p_generate_cback != NULL) {
return;
}
p_mgnt_cb->p_generate_cback = p_cback;
p_mgnt_cb->p = p;
if (!btsnd_hcic_ble_rand((void *)btm_gen_non_resolve_paddr_cmpl)) {
btm_gen_non_resolve_paddr_cmpl(NULL);
}
}
/*******************************************************************************
** Utility functions for Random address resolving
*******************************************************************************/
/*******************************************************************************
**
** Function btm_ble_resolve_address_cmpl
**
** Description This function sends the random address resolving complete
** callback.
**
** Returns None.
**
*******************************************************************************/
#if SMP_INCLUDED == TRUE
static void btm_ble_resolve_address_cmpl(void)
{
tBTM_LE_RANDOM_CB *p_mgnt_cb = &btm_cb.ble_ctr_cb.addr_mgnt_cb;
BTM_TRACE_EVENT ("btm_ble_resolve_address_cmpl p_mgnt_cb->p_dev_rec = 0x%08x", (uint32_t)p_mgnt_cb->p_dev_rec);
p_mgnt_cb->busy = FALSE;
(* p_mgnt_cb->p_resolve_cback)(p_mgnt_cb->p_dev_rec, p_mgnt_cb->p);
}
/*******************************************************************************
**
** Function btm_ble_proc_resolve_x
**
** Description This function compares the X with random address 3 MSO bytes
** to find a match, if not match, continue for next record.
**
** Returns None.
**
*******************************************************************************/
static BOOLEAN btm_ble_proc_resolve_x(tSMP_ENC *p)
{
tBTM_LE_RANDOM_CB *p_mgnt_cb = &btm_cb.ble_ctr_cb.addr_mgnt_cb;
UINT8 comp[3];
BTM_TRACE_EVENT ("btm_ble_proc_resolve_x");
/* compare the hash with 3 LSB of bd address */
comp[0] = p_mgnt_cb->random_bda[5];
comp[1] = p_mgnt_cb->random_bda[4];
comp[2] = p_mgnt_cb->random_bda[3];
if (p) {
if (!memcmp(p->param_buf, &comp[0], 3)) {
/* match is found */
BTM_TRACE_EVENT ("match is found");
btm_ble_resolve_address_cmpl();
return TRUE;
}
}
return FALSE;
}
#endif ///SMP_INCLUDED == TRUE
/*******************************************************************************
**
** Function btm_ble_init_pseudo_addr
**
** Description This function is used to initialize pseudo address.
** If pseudo address is not available, use dummy address
**
** Returns TRUE is updated; FALSE otherwise.
**
*******************************************************************************/
BOOLEAN btm_ble_init_pseudo_addr (tBTM_SEC_DEV_REC *p_dev_rec, BD_ADDR new_pseudo_addr)
{
#if (SMP_INCLUDED == TRUE)
BD_ADDR dummy_bda = {0};
if (memcmp(p_dev_rec->ble.pseudo_addr, dummy_bda, BD_ADDR_LEN) == 0) {
memcpy(p_dev_rec->ble.pseudo_addr, new_pseudo_addr, BD_ADDR_LEN);
return TRUE;
}
#endif ///SMP_INCLUDED == TRUE
return FALSE;
}
/*******************************************************************************
**
** Function btm_ble_addr_resolvable
**
** Description This function checks if a RPA is resolvable by the device key.
**
** Returns TRUE is resolvable; FALSE otherwise.
**
*******************************************************************************/
BOOLEAN btm_ble_addr_resolvable (BD_ADDR rpa, tBTM_SEC_DEV_REC *p_dev_rec)
{
BOOLEAN rt = FALSE;
#if (SMP_INCLUDED == TRUE)
if (!BTM_BLE_IS_RESOLVE_BDA(rpa)) {
return rt;
}
UINT8 rand[3];
tSMP_ENC output;
if ((p_dev_rec->device_type & BT_DEVICE_TYPE_BLE) &&
(p_dev_rec->ble.key_type & BTM_LE_KEY_PID)) {
BTM_TRACE_DEBUG("%s try to resolve", __func__);
/* use the 3 MSB of bd address as prand */
rand[0] = rpa[2];
rand[1] = rpa[1];
rand[2] = rpa[0];
/* generate X = E irk(R0, R1, R2) and R is random address 3 LSO */
SMP_Encrypt(p_dev_rec->ble.keys.irk, BT_OCTET16_LEN,
&rand[0], 3, &output);
rand[0] = rpa[5];
rand[1] = rpa[4];
rand[2] = rpa[3];
if (!memcmp(output.param_buf, &rand[0], 3)) {
btm_ble_init_pseudo_addr (p_dev_rec, rpa);
rt = TRUE;
}
}
#endif ///SMP_INCLUDED == TRUE
return rt;
}
#if (BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE)
/*******************************************************************************
**
** Function btm_ble_match_random_bda
**
** Description This function match the random address to the appointed device
** record, starting from calculating IRK. If record index exceed
** the maximum record number, matching failed and send callback.
**
** Returns None.
**
*******************************************************************************/
static BOOLEAN btm_ble_match_random_bda(tBTM_SEC_DEV_REC *p_dev_rec)
{
/* use the 3 MSB of bd address as prand */
tBTM_LE_RANDOM_CB *p_mgnt_cb = &btm_cb.ble_ctr_cb.addr_mgnt_cb;
UINT8 rand[3];
rand[0] = p_mgnt_cb->random_bda[2];
rand[1] = p_mgnt_cb->random_bda[1];
rand[2] = p_mgnt_cb->random_bda[0];
BTM_TRACE_EVENT("%s p_dev_rec = 0x%08x", __func__, (uint32_t)p_dev_rec);
{
tSMP_ENC output;
BTM_TRACE_DEBUG("sec_flags = %02x device_type = %d", p_dev_rec->sec_flags,
p_dev_rec->device_type);
if ((p_dev_rec->device_type & BT_DEVICE_TYPE_BLE) &&
(p_dev_rec->ble.key_type & BTM_LE_KEY_PID)) {
/* generate X = E irk(R0, R1, R2) and R is random address 3 LSO */
SMP_Encrypt(p_dev_rec->ble.keys.irk, BT_OCTET16_LEN,
&rand[0], 3, &output);
return btm_ble_proc_resolve_x(&output);
} else {
// not completed
return FALSE;
}
}
}
#endif ///BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE
/*******************************************************************************
**
** Function btm_ble_resolve_random_addr
**
** Description This function is called to resolve a random address.
**
** Returns pointer to the security record of the device whom a random
** address is matched to.
**
*******************************************************************************/
void btm_ble_resolve_random_addr(BD_ADDR random_bda, tBTM_BLE_RESOLVE_CBACK *p_cback, void *p)
{
#if (SMP_INCLUDED == TRUE)
tBTM_LE_RANDOM_CB *p_mgnt_cb = &btm_cb.ble_ctr_cb.addr_mgnt_cb;
list_node_t *p_node = NULL;
tBTM_SEC_DEV_REC *p_dev_rec = NULL;
BTM_TRACE_EVENT ("btm_ble_resolve_random_addr");
if ( !p_mgnt_cb->busy) {
p_mgnt_cb->p = p;
p_mgnt_cb->busy = TRUE;
p_mgnt_cb->p_dev_rec = NULL;
p_mgnt_cb->p_resolve_cback = p_cback;
memcpy(p_mgnt_cb->random_bda, random_bda, BD_ADDR_LEN);
/* start to resolve random address */
/* check for next security record */
for (p_node = list_begin(btm_cb.p_sec_dev_rec_list); p_node; p_node = list_next(p_node)) {
p_dev_rec = list_node(p_node);
p_mgnt_cb->p_dev_rec = p_dev_rec;
if (btm_ble_match_random_bda(p_dev_rec)) {
break;
}
p_mgnt_cb->p_dev_rec = NULL;
}
btm_ble_resolve_address_cmpl();
} else {
(*p_cback)(NULL, p);
}
#endif
}
/*******************************************************************************
** address mapping between pseudo address and real connection address
*******************************************************************************/
/*******************************************************************************
**
** Function btm_find_dev_by_identity_addr
**
** Description find the security record whose LE static address is matching
**
*******************************************************************************/
tBTM_SEC_DEV_REC *btm_find_dev_by_identity_addr(BD_ADDR bd_addr, UINT8 addr_type)
{
#if BLE_PRIVACY_SPT == TRUE
tBTM_SEC_DEV_REC *p_dev_rec = NULL;
list_node_t *p_node = NULL;
tSecDevContext context;
context.type = SEC_DEV_ID_ADDR;
context.context.p_bd_addr = bd_addr;
context.free_check = FALSE;
p_node = list_foreach(btm_cb.p_sec_dev_rec_list, btm_find_sec_dev_in_list, &context);
if (p_node) {
p_dev_rec = list_node(p_node);
if ((p_dev_rec->ble.static_addr_type & (~BLE_ADDR_TYPE_ID_BIT)) !=
(addr_type & (~BLE_ADDR_TYPE_ID_BIT))) {
BTM_TRACE_WARNING("%s find pseudo->random match with diff addr type: %d vs %d",
__func__, p_dev_rec->ble.static_addr_type, addr_type);
}
}
return p_dev_rec;
#endif
return NULL;
}
/*******************************************************************************
**
** Function btm_identity_addr_to_random_pseudo
**
** Description This function map a static BD address to a pseudo random address
** in security database.
**
*******************************************************************************/
BOOLEAN btm_identity_addr_to_random_pseudo(BD_ADDR bd_addr, UINT8 *p_addr_type, BOOLEAN refresh)
{
#if BLE_PRIVACY_SPT == TRUE
tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev_by_identity_addr(bd_addr, *p_addr_type);
BTM_TRACE_EVENT ("%s", __func__);
/* evt reported on static address, map static address to random pseudo */
if (p_dev_rec != NULL) {
/* if RPA offloading is supported, or 4.2 controller, do RPA refresh */
if (refresh && controller_get_interface()->get_ble_resolving_list_max_size() != 0) {
btm_ble_read_resolving_list_entry(p_dev_rec);
}
/* assign the original address to be the current report address */
if (!btm_ble_init_pseudo_addr (p_dev_rec, bd_addr)) {
memcpy(bd_addr, p_dev_rec->ble.pseudo_addr, BD_ADDR_LEN);
}
*p_addr_type = p_dev_rec->ble.ble_addr_type;
return TRUE;
}
#endif
return FALSE;
}
/*******************************************************************************
**
** Function btm_random_pseudo_to_identity_addr
**
** Description This function map a random pseudo address to a public address
** random_pseudo is input and output parameter
**
*******************************************************************************/
BOOLEAN btm_random_pseudo_to_identity_addr(BD_ADDR random_pseudo, UINT8 *p_static_addr_type)
{
#if BLE_PRIVACY_SPT == TRUE
tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (random_pseudo);
if (p_dev_rec != NULL) {
if (p_dev_rec->ble.in_controller_list & BTM_RESOLVING_LIST_BIT) {
* p_static_addr_type = p_dev_rec->ble.static_addr_type;
memcpy(random_pseudo, p_dev_rec->ble.static_addr, BD_ADDR_LEN);
if (controller_get_interface()->supports_ble_privacy() && p_dev_rec->ble.ble_addr_type != BLE_ADDR_PUBLIC) {
*p_static_addr_type |= BLE_ADDR_TYPE_ID_BIT;
}
return TRUE;
}
}
#endif
return FALSE;
}
/*******************************************************************************
**
** Function btm_ble_refresh_peer_resolvable_private_addr
**
** Description This function refresh the currently used resolvable remote private address into security
** database and set active connection address.
**
*******************************************************************************/
void btm_ble_refresh_peer_resolvable_private_addr(BD_ADDR pseudo_bda, BD_ADDR rpa,
UINT8 rra_type)
{
#if BLE_PRIVACY_SPT == TRUE
UINT8 rra_dummy = FALSE;
BD_ADDR dummy_bda = {0};
if (memcmp(dummy_bda, rpa, BD_ADDR_LEN) == 0) {
rra_dummy = TRUE;
}
/* update security record here, in adv event or connection complete process */
tBTM_SEC_DEV_REC *p_sec_rec = btm_find_dev(pseudo_bda);
if (p_sec_rec != NULL) {
memcpy(p_sec_rec->ble.cur_rand_addr, rpa, BD_ADDR_LEN);
/* unknown, if dummy address, set to static */
if (rra_type == BTM_BLE_ADDR_PSEUDO) {
p_sec_rec->ble.active_addr_type = rra_dummy ? BTM_BLE_ADDR_STATIC : BTM_BLE_ADDR_RRA;
} else {
p_sec_rec->ble.active_addr_type = rra_type;
}
} else {
BTM_TRACE_ERROR("No matching known device in record");
return;
}
BTM_TRACE_DEBUG("%s: active_addr_type: %d ",
__func__, p_sec_rec->ble.active_addr_type);
/* connection refresh remote address */
tACL_CONN *p_acl = btm_bda_to_acl(p_sec_rec->bd_addr, BT_TRANSPORT_LE);
if (p_acl == NULL) {
p_acl = btm_bda_to_acl(p_sec_rec->ble.pseudo_addr, BT_TRANSPORT_LE);
}
if (p_acl != NULL) {
if (rra_type == BTM_BLE_ADDR_PSEUDO) {
/* use static address, resolvable_private_addr is empty */
if (rra_dummy) {
p_acl->active_remote_addr_type = p_sec_rec->ble.static_addr_type;
memcpy(p_acl->active_remote_addr, p_sec_rec->ble.static_addr, BD_ADDR_LEN);
} else {
p_acl->active_remote_addr_type = BLE_ADDR_RANDOM;
memcpy(p_acl->active_remote_addr, rpa, BD_ADDR_LEN);
}
} else {
p_acl->active_remote_addr_type = rra_type;
memcpy(p_acl->active_remote_addr, rpa, BD_ADDR_LEN);
}
BTM_TRACE_DEBUG("p_acl->active_remote_addr_type: %d ", p_acl->active_remote_addr_type);
BTM_TRACE_DEBUG("%s conn_addr: %02x:%02x:%02x:%02x:%02x:%02x",
__func__, p_acl->active_remote_addr[0], p_acl->active_remote_addr[1],
p_acl->active_remote_addr[2], p_acl->active_remote_addr[3],
p_acl->active_remote_addr[4], p_acl->active_remote_addr[5]);
}
#endif
}
/*******************************************************************************
**
** Function btm_ble_refresh_local_resolvable_private_addr
**
** Description This function refresh the currently used resolvable private address for the
** active link to the remote device
**
*******************************************************************************/
void btm_ble_refresh_local_resolvable_private_addr(BD_ADDR pseudo_addr,
BD_ADDR local_rpa)
{
#if BLE_PRIVACY_SPT == TRUE
tACL_CONN *p = btm_bda_to_acl(pseudo_addr, BT_TRANSPORT_LE);
BD_ADDR dummy_bda = {0};
if (p != NULL) {
if (btm_cb.ble_ctr_cb.addr_mgnt_cb.own_addr_type >= BLE_ADDR_RANDOM) {
p->conn_addr_type = BLE_ADDR_RANDOM;
if (memcmp(local_rpa, dummy_bda, BD_ADDR_LEN)) {
memcpy(p->conn_addr, local_rpa, BD_ADDR_LEN);
} else {
memcpy(p->conn_addr, btm_cb.ble_ctr_cb.addr_mgnt_cb.private_addr, BD_ADDR_LEN);
}
} else {
p->conn_addr_type = BLE_ADDR_PUBLIC;
memcpy(p->conn_addr, &controller_get_interface()->get_address()->address, BD_ADDR_LEN);
}
}
#endif
}
#endif
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,953 @@
/******************************************************************************
*
* 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.
*
******************************************************************************/
#include <string.h>
//#include <stdio.h>
#include <stddef.h>
#include "common/bt_target.h"
#include "stack/btm_ble_api.h"
#include "stack/bt_types.h"
//#include "bt_utils.h"
#include "stack/btu.h"
#include "btm_int.h"
#include "device/controller.h"
#include "stack/hcimsgs.h"
#if (BLE_INCLUDED == TRUE)
#if BTM_DYNAMIC_MEMORY == FALSE
tBTM_BLE_BATCH_SCAN_CB ble_batchscan_cb;
tBTM_BLE_ADV_TRACK_CB ble_advtrack_cb;
#else
tBTM_BLE_BATCH_SCAN_CB *ble_batchscan_cb_ptr;
tBTM_BLE_ADV_TRACK_CB *ble_advtrack_cb_ptr;
#define ble_batchscan_cb (*ble_batchscan_cb_ptr)
#define ble_advtrack_cb (*ble_advtrack_cb_ptr)
#endif
/* length of each batch scan command */
#define BTM_BLE_BATCH_SCAN_STORAGE_CFG_LEN 4
#define BTM_BLE_BATCH_SCAN_PARAM_CONFIG_LEN 12
#define BTM_BLE_BATCH_SCAN_ENB_DISB_LEN 2
#define BTM_BLE_BATCH_SCAN_READ_RESULTS_LEN 2
#define BTM_BLE_BATCH_SCAN_CB_EVT_MASK 0xF0
#define BTM_BLE_BATCH_SCAN_SUBCODE_MASK 0x0F
/*******************************************************************************
** Local functions
*******************************************************************************/
void btm_ble_batchscan_vsc_cmpl_cback (tBTM_VSC_CMPL *p_params);
void btm_ble_batchscan_cleanup(void);
/*******************************************************************************
**
** Function btm_ble_batchscan_filter_track_adv_vse_cback
**
** Description VSE callback for batch scan, filter, and tracking events.
**
** Returns None
**
*******************************************************************************/
void btm_ble_batchscan_filter_track_adv_vse_cback(UINT8 len, UINT8 *p)
{
tBTM_BLE_TRACK_ADV_DATA adv_data;
UINT8 sub_event = 0;
tBTM_BLE_VSC_CB cmn_ble_vsc_cb;
STREAM_TO_UINT8(sub_event, p);
BTM_TRACE_EVENT("btm_ble_batchscan_filter_track_adv_vse_cback called with event:%x", sub_event);
if (HCI_VSE_SUBCODE_BLE_THRESHOLD_SUB_EVT == sub_event &&
NULL != ble_batchscan_cb.p_thres_cback) {
ble_batchscan_cb.p_thres_cback(ble_batchscan_cb.ref_value);
return;
}
if (HCI_VSE_SUBCODE_BLE_TRACKING_SUB_EVT == sub_event && NULL != ble_advtrack_cb.p_track_cback) {
if (len < 10) {
return;
}
memset(&adv_data, 0 , sizeof(tBTM_BLE_TRACK_ADV_DATA));
BTM_BleGetVendorCapabilities(&cmn_ble_vsc_cb);
adv_data.client_if = (UINT8)ble_advtrack_cb.ref_value;
if (cmn_ble_vsc_cb.version_supported > BTM_VSC_CHIP_CAPABILITY_L_VERSION) {
STREAM_TO_UINT8(adv_data.filt_index, p);
STREAM_TO_UINT8(adv_data.advertiser_state, p);
STREAM_TO_UINT8(adv_data.advertiser_info_present, p);
STREAM_TO_BDADDR(adv_data.bd_addr.address, p);
STREAM_TO_UINT8(adv_data.addr_type, p);
/* Extract the adv info details */
if (ADV_INFO_PRESENT == adv_data.advertiser_info_present) {
STREAM_TO_UINT8(adv_data.tx_power, p);
STREAM_TO_UINT8(adv_data.rssi_value, p);
STREAM_TO_UINT16(adv_data.time_stamp, p);
STREAM_TO_UINT8(adv_data.adv_pkt_len, p);
if (adv_data.adv_pkt_len > 0) {
adv_data.p_adv_pkt_data = osi_malloc(adv_data.adv_pkt_len);
memcpy(adv_data.p_adv_pkt_data, p, adv_data.adv_pkt_len);
}
STREAM_TO_UINT8(adv_data.scan_rsp_len, p);
if (adv_data.scan_rsp_len > 0) {
adv_data.p_scan_rsp_data = osi_malloc(adv_data.scan_rsp_len);
memcpy(adv_data.p_scan_rsp_data, p, adv_data.scan_rsp_len);
}
}
} else {
/* Based on L-release version */
STREAM_TO_UINT8(adv_data.filt_index, p);
STREAM_TO_UINT8(adv_data.addr_type, p);
STREAM_TO_BDADDR(adv_data.bd_addr.address, p);
STREAM_TO_UINT8(adv_data.advertiser_state, p);
}
BTM_TRACE_EVENT("track_adv_vse_cback called: %d, %d, %d", adv_data.filt_index,
adv_data.addr_type, adv_data.advertiser_state);
ble_advtrack_cb.p_track_cback(&adv_data);
return;
}
}
/*******************************************************************************
**
** Function btm_ble_batchscan_enq_op_q
**
** Description enqueue a batchscan operation in q to check command complete
** status
**
** Returns void
**
*******************************************************************************/
void btm_ble_batchscan_enq_op_q(UINT8 opcode, tBTM_BLE_BATCH_SCAN_STATE cur_state,
UINT8 cb_evt, tBTM_BLE_REF_VALUE ref_value)
{
ble_batchscan_cb.op_q.sub_code[ble_batchscan_cb.op_q.next_idx] = (opcode | (cb_evt << 4));
ble_batchscan_cb.op_q.cur_state[ble_batchscan_cb.op_q.next_idx] = cur_state;
ble_batchscan_cb.op_q.ref_value[ble_batchscan_cb.op_q.next_idx] = ref_value;
BTM_TRACE_DEBUG("btm_ble_batchscan_enq_op_q: subcode:%d, Cur_state:%d, ref_value:%d",
ble_batchscan_cb.op_q.sub_code[ble_batchscan_cb.op_q.next_idx],
ble_batchscan_cb.op_q.cur_state[ble_batchscan_cb.op_q.next_idx],
ble_batchscan_cb.op_q.ref_value[ble_batchscan_cb.op_q.next_idx]);
ble_batchscan_cb.op_q.next_idx = (ble_batchscan_cb.op_q.next_idx + 1)
% BTM_BLE_BATCH_SCAN_MAX;
}
/*******************************************************************************
**
** Function btm_ble_batchscan_enq_rep_q
**
** Description enqueue a batchscan report operation in q to check command complete
** status
**
** Returns void
**
*******************************************************************************/
tBTM_STATUS btm_ble_batchscan_enq_rep_q(UINT8 report_format, tBTM_BLE_REF_VALUE ref_value)
{
int i = 0;
for (i = 0; i < BTM_BLE_BATCH_REP_MAIN_Q_SIZE; i++) {
if (report_format == ble_batchscan_cb.main_rep_q.rep_mode[i]) {
return BTM_ILLEGAL_VALUE;
}
}
ble_batchscan_cb.main_rep_q.rep_mode[ble_batchscan_cb.main_rep_q.next_idx] = report_format;
ble_batchscan_cb.main_rep_q.ref_value[ble_batchscan_cb.main_rep_q.next_idx] = ref_value;
ble_batchscan_cb.main_rep_q.num_records[ble_batchscan_cb.main_rep_q.next_idx] = 0;
ble_batchscan_cb.main_rep_q.data_len[ble_batchscan_cb.main_rep_q.next_idx] = 0;
ble_batchscan_cb.main_rep_q.p_data[ble_batchscan_cb.main_rep_q.next_idx] = NULL;
BTM_TRACE_DEBUG("btm_ble_batchscan_enq_rep_q: index:%d, rep %d, ref %d",
ble_batchscan_cb.main_rep_q.next_idx, report_format, ref_value);
ble_batchscan_cb.main_rep_q.next_idx = (ble_batchscan_cb.main_rep_q.next_idx + 1)
% BTM_BLE_BATCH_REP_MAIN_Q_SIZE;
return BTM_SUCCESS;
}
/*******************************************************************************
**
** Function btm_ble_batchscan_enq_rep_data
**
** Description setup the data in the main report queue
**
** Returns void
**
*******************************************************************************/
void btm_ble_batchscan_enq_rep_data(UINT8 report_format, UINT8 num_records, UINT8 *p_data,
UINT8 data_len)
{
int index = 0, len = 0;
UINT8 *p_orig_data = NULL, *p_app_data = NULL;
for (index = 0; index < BTM_BLE_BATCH_REP_MAIN_Q_SIZE; index++) {
if (report_format == ble_batchscan_cb.main_rep_q.rep_mode[index]) {
break;
}
}
BTM_TRACE_DEBUG("btm_ble_batchscan_enq_rep_data: index:%d, rep %d, num %d len : %d",
index, report_format, num_records, data_len);
if (index < BTM_BLE_BATCH_REP_MAIN_Q_SIZE && data_len > 0 && num_records > 0) {
len = ble_batchscan_cb.main_rep_q.data_len[index];
p_orig_data = ble_batchscan_cb.main_rep_q.p_data[index];
if (NULL != p_orig_data) {
p_app_data = osi_malloc(len + data_len);
memcpy(p_app_data, p_orig_data, len);
memcpy(p_app_data + len, p_data, data_len);
osi_free(p_orig_data);
ble_batchscan_cb.main_rep_q.p_data[index] = p_app_data;
ble_batchscan_cb.main_rep_q.num_records[index] += num_records;
ble_batchscan_cb.main_rep_q.data_len[index] += data_len;
} else {
p_app_data = osi_malloc(data_len);
memcpy(p_app_data, p_data, data_len);
ble_batchscan_cb.main_rep_q.p_data[index] = p_app_data;
ble_batchscan_cb.main_rep_q.num_records[index] = num_records;
ble_batchscan_cb.main_rep_q.data_len[index] = data_len;
}
}
}
/*******************************************************************************
**
** Function btm_ble_batchscan_deq_rep_q
**
** Description dequeue a batchscan report in q when command complete
** is received
**
** Returns void
**
*******************************************************************************/
void btm_ble_batchscan_deq_rep_data(UINT8 report_format, tBTM_BLE_REF_VALUE *p_ref_value,
UINT8 *p_num_records, UINT8 **p_data, UINT16 *p_data_len)
{
int index = 0;
for (index = 0; index < BTM_BLE_BATCH_REP_MAIN_Q_SIZE; index++) {
if (report_format == ble_batchscan_cb.main_rep_q.rep_mode[index]) {
break;
}
}
if (BTM_BLE_BATCH_REP_MAIN_Q_SIZE == index) {
BTM_TRACE_ERROR("btm_ble_batchscan_deq_rep_data: rep_format:%d not found", report_format);
return;
}
*p_num_records = ble_batchscan_cb.main_rep_q.num_records[index];
*p_ref_value = ble_batchscan_cb.main_rep_q.ref_value[index];
*p_data = ble_batchscan_cb.main_rep_q.p_data[index];
*p_data_len = ble_batchscan_cb.main_rep_q.data_len[index];
ble_batchscan_cb.main_rep_q.p_data[index] = NULL;
ble_batchscan_cb.main_rep_q.data_len[index] = 0;
ble_batchscan_cb.main_rep_q.rep_mode[index] = 0;
ble_batchscan_cb.main_rep_q.ref_value[index] = 0;
ble_batchscan_cb.main_rep_q.num_records[index] = 0;
BTM_TRACE_DEBUG("btm_ble_batchscan_deq_rep_data: index:%d, rep %d, num %d, data_len %d",
index, report_format, *p_num_records, *p_data_len);
ble_batchscan_cb.main_rep_q.pending_idx = (ble_batchscan_cb.main_rep_q.pending_idx + 1)
% BTM_BLE_BATCH_SCAN_MAX;
}
/*******************************************************************************
**
** Function btm_ble_batchscan_deq_op_q
**
** Description dequeue a batch scan operation from q when command complete
** is received
**
** Returns void
**
*******************************************************************************/
void btm_ble_batchscan_deq_op_q(UINT8 *p_opcode, tBTM_BLE_BATCH_SCAN_STATE *cur_state,
UINT8 *p_cb_evt, tBTM_BLE_REF_VALUE *p_ref)
{
*p_cb_evt = (ble_batchscan_cb.op_q.sub_code[ble_batchscan_cb.op_q.pending_idx] >> 4);
*p_opcode = (ble_batchscan_cb.op_q.sub_code[ble_batchscan_cb.op_q.pending_idx]
& BTM_BLE_BATCH_SCAN_SUBCODE_MASK);
*p_ref = ble_batchscan_cb.op_q.ref_value[ble_batchscan_cb.op_q.pending_idx];
*cur_state = (ble_batchscan_cb.op_q.cur_state[ble_batchscan_cb.op_q.pending_idx]);
ble_batchscan_cb.op_q.pending_idx = (ble_batchscan_cb.op_q.pending_idx + 1)
% BTM_BLE_BATCH_SCAN_MAX;
}
/*******************************************************************************
**
** Function btm_ble_read_batchscan_reports
**
** Description This function reads the reports from controller
**
** Parameters scan_mode - The mode for which the reports are to be read out from the controller
** ref_value - Reference value
**
** Returns status
**
*******************************************************************************/
tBTM_STATUS btm_ble_read_batchscan_reports(tBTM_BLE_BATCH_SCAN_MODE scan_mode,
tBTM_BLE_REF_VALUE ref_value)
{
tBTM_STATUS status = BTM_NO_RESOURCES;
UINT8 param[BTM_BLE_BATCH_SCAN_READ_RESULTS_LEN], *pp;
pp = param;
memset(param, 0, BTM_BLE_BATCH_SCAN_READ_RESULTS_LEN);
UINT8_TO_STREAM (pp, BTM_BLE_BATCH_SCAN_READ_RESULTS);
UINT8_TO_STREAM (pp, scan_mode);
if ((status = BTM_VendorSpecificCommand (HCI_BLE_BATCH_SCAN_OCF,
BTM_BLE_BATCH_SCAN_READ_RESULTS_LEN, param, btm_ble_batchscan_vsc_cmpl_cback))
!= BTM_CMD_STARTED) {
BTM_TRACE_ERROR("btm_ble_read_batchscan_reports %d", status);
return BTM_ILLEGAL_VALUE;
}
if (BTM_CMD_STARTED == status) {
/* The user needs to be provided scan read reports event */
btm_ble_batchscan_enq_op_q(BTM_BLE_BATCH_SCAN_READ_RESULTS, ble_batchscan_cb.cur_state,
BTM_BLE_BATCH_SCAN_READ_REPTS_EVT, ref_value);
}
return status;
}
/*******************************************************************************
**
** Function btm_ble_batchscan_vsc_cmpl_cback
**
** Description Batch scan VSC complete callback
**
** Parameters p_params - VSC completed callback parameters
**
** Returns void
**
*******************************************************************************/
void btm_ble_batchscan_vsc_cmpl_cback (tBTM_VSC_CMPL *p_params)
{
UINT8 *p = p_params->p_param_buf;
UINT16 len = p_params->param_len;
tBTM_BLE_REF_VALUE ref_value = 0;
UINT8 status = 0, subcode = 0, opcode = 0;
UINT8 report_format = 0, num_records = 0, cb_evt = 0;
UINT16 data_len = 0;
tBTM_BLE_BATCH_SCAN_STATE cur_state = 0;
tBTM_STATUS btm_status = 0;
UINT8 *p_data = NULL;
if (len < 2) {
BTM_TRACE_ERROR("wrong length for btm_ble_batch_scan_vsc_cmpl_cback");
btm_ble_batchscan_deq_op_q(&opcode, &cur_state, &cb_evt, &ref_value);
return;
}
STREAM_TO_UINT8(status, p);
STREAM_TO_UINT8(subcode, p);
btm_ble_batchscan_deq_op_q(&opcode, &cur_state, &cb_evt, &ref_value);
BTM_TRACE_DEBUG("btm_ble_batchscan op_code = %02x state = %02x cb_evt = %02x,ref_value=%d",
opcode, cur_state, cb_evt, ref_value);
if (opcode != subcode) {
BTM_TRACE_ERROR("Got unexpected VSC cmpl, expected: %d got: %d", subcode, opcode);
return;
}
switch (subcode) {
case BTM_BLE_BATCH_SCAN_ENB_DISAB_CUST_FEATURE: {
if (BTM_SUCCESS == status && BTM_BLE_SCAN_ENABLE_CALLED == cur_state) {
ble_batchscan_cb.cur_state = BTM_BLE_SCAN_ENABLED_STATE;
} else if (BTM_BLE_SCAN_ENABLE_CALLED == cur_state) {
BTM_TRACE_ERROR("SCAN_ENB_DISAB_CUST_FEATURE - Invalid state after enb");
ble_batchscan_cb.cur_state = BTM_BLE_SCAN_INVALID_STATE;
}
BTM_TRACE_DEBUG("BTM_BLE_BATCH_SCAN_ENB_DISAB_CUST_FEAT status = %d, state: %d,evt=%d",
status, ble_batchscan_cb.cur_state, cb_evt);
if (cb_evt != 0 && NULL != ble_batchscan_cb.p_setup_cback) {
ble_batchscan_cb.p_setup_cback(cb_evt, ref_value, status);
}
break;
}
case BTM_BLE_BATCH_SCAN_SET_STORAGE_PARAM: {
BTM_TRACE_DEBUG("BTM_BLE_BATCH_SCAN_SET_STORAGE_PARAM status = %d, evt=%d",
status, cb_evt);
if (cb_evt != 0 && NULL != ble_batchscan_cb.p_setup_cback) {
ble_batchscan_cb.p_setup_cback(cb_evt, ref_value, status);
}
break;
}
case BTM_BLE_BATCH_SCAN_SET_PARAMS: {
BTM_TRACE_DEBUG("BTM_BLE_BATCH_SCAN_SET_PARAMS status = %d,evt=%d", status, cb_evt);
if (BTM_BLE_SCAN_DISABLE_CALLED == cur_state) {
if (BTM_SUCCESS == status) {
ble_batchscan_cb.cur_state = BTM_BLE_SCAN_DISABLED_STATE;
} else {
BTM_TRACE_ERROR("BTM_BLE_BATCH_SCAN_SET_PARAMS - Invalid state after disabled");
ble_batchscan_cb.cur_state = BTM_BLE_SCAN_INVALID_STATE;
}
}
if (cb_evt != 0 && NULL != ble_batchscan_cb.p_setup_cback) {
ble_batchscan_cb.p_setup_cback(cb_evt, ref_value, status);
}
break;
}
case BTM_BLE_BATCH_SCAN_READ_RESULTS: {
if (cb_evt != 0 && NULL != ble_batchscan_cb.p_scan_rep_cback) {
STREAM_TO_UINT8(report_format, p);
STREAM_TO_UINT8(num_records, p);
p = (uint8_t *)(p_params->p_param_buf + 4);
BTM_TRACE_DEBUG("BTM_BLE_BATCH_SCAN_READ_RESULTS status=%d,len=%d,rec=%d",
status, len - 4, num_records);
if (0 == num_records) {
btm_ble_batchscan_deq_rep_data(report_format, &ref_value, &num_records,
&p_data, &data_len);
if (NULL != ble_batchscan_cb.p_scan_rep_cback) {
ble_batchscan_cb.p_scan_rep_cback(ref_value, report_format, num_records,
data_len, p_data, status);
}
} else {
if ((len - 4) > 0) {
btm_ble_batchscan_enq_rep_data(report_format, num_records, p, len - 4);
/* More records could be in the buffer and needs to be pulled out */
btm_status = btm_ble_read_batchscan_reports(report_format, ref_value);
if (BTM_CMD_STARTED != btm_status) {
btm_ble_batchscan_deq_rep_data(report_format, &ref_value, &num_records,
&p_data, &data_len);
/* Send whatever is available, in case of a command failure */
if (NULL != ble_batchscan_cb.p_scan_rep_cback && NULL != p_data) {
ble_batchscan_cb.p_scan_rep_cback(ref_value, report_format,
num_records, data_len, p_data, status);
}
}
}
}
}
break;
}
default:
break;
}
return;
}
/*******************************************************************************
**
** Function btm_ble_set_storage_config
**
** Description This function writes the storage configuration in controller
**
** Parameters batch_scan_full_max -Max storage space (in %) allocated to full scanning
** batch_scan_trunc_max -Max storage space (in %) allocated to truncated scanning
** batch_scan_notify_threshold - Setup notification level based on total space
**
** Returns status
**
*******************************************************************************/
tBTM_STATUS btm_ble_set_storage_config(UINT8 batch_scan_full_max, UINT8 batch_scan_trunc_max,
UINT8 batch_scan_notify_threshold)
{
tBTM_STATUS status = BTM_NO_RESOURCES;
UINT8 param[BTM_BLE_BATCH_SCAN_STORAGE_CFG_LEN], *pp;
pp = param;
memset(param, 0, BTM_BLE_BATCH_SCAN_STORAGE_CFG_LEN);
UINT8_TO_STREAM (pp, BTM_BLE_BATCH_SCAN_SET_STORAGE_PARAM);
UINT8_TO_STREAM (pp, batch_scan_full_max);
UINT8_TO_STREAM (pp, batch_scan_trunc_max);
UINT8_TO_STREAM (pp, batch_scan_notify_threshold);
if ((status = BTM_VendorSpecificCommand (HCI_BLE_BATCH_SCAN_OCF,
BTM_BLE_BATCH_SCAN_STORAGE_CFG_LEN, param,
btm_ble_batchscan_vsc_cmpl_cback)) != BTM_CMD_STARTED) {
BTM_TRACE_ERROR("btm_ble_set_storage_config %d", status);
return BTM_ILLEGAL_VALUE;
}
return status;
}
/*******************************************************************************
**
** Function btm_ble_set_batchscan_param
**
** Description This function writes the batch scan params in controller
**
** Parameters scan_mode -Batch scan mode
** scan_interval - Scan interval
** scan_window - Scan window
** discard_rule -Discard rules
** addr_type - Address type
**
** Returns status
**
*******************************************************************************/
tBTM_STATUS btm_ble_set_batchscan_param(tBTM_BLE_BATCH_SCAN_MODE scan_mode,
UINT32 scan_interval, UINT32 scan_window, tBLE_ADDR_TYPE addr_type,
tBTM_BLE_DISCARD_RULE discard_rule)
{
tBTM_STATUS status = BTM_NO_RESOURCES;
UINT8 scan_param[BTM_BLE_BATCH_SCAN_PARAM_CONFIG_LEN], *pp_scan;
pp_scan = scan_param;
memset(scan_param, 0, BTM_BLE_BATCH_SCAN_PARAM_CONFIG_LEN);
// Override param and decide addr_type based on own addr type
// TODO: Remove upper layer parameter?
addr_type = btm_cb.ble_ctr_cb.addr_mgnt_cb.own_addr_type;
UINT8_TO_STREAM (pp_scan, BTM_BLE_BATCH_SCAN_SET_PARAMS);
UINT8_TO_STREAM (pp_scan, scan_mode);
UINT32_TO_STREAM (pp_scan, scan_window);
UINT32_TO_STREAM (pp_scan, scan_interval);
UINT8_TO_STREAM (pp_scan, addr_type);
UINT8_TO_STREAM (pp_scan, discard_rule);
if ((status = BTM_VendorSpecificCommand (HCI_BLE_BATCH_SCAN_OCF,
BTM_BLE_BATCH_SCAN_PARAM_CONFIG_LEN,
scan_param, btm_ble_batchscan_vsc_cmpl_cback)) != BTM_CMD_STARTED) {
BTM_TRACE_ERROR("btm_ble_set_batchscan_param %d", status);
return BTM_ILLEGAL_VALUE;
}
return status;
}
/*******************************************************************************
**
** Function btm_ble_enable_disable_batchscan
**
** Description This function enables the customer specific feature in controller
**
** Parameters enable_disable: true - enable, false - disable
**
** Returns status
**
*******************************************************************************/
tBTM_STATUS btm_ble_enable_disable_batchscan(BOOLEAN should_enable)
{
tBTM_STATUS status = BTM_NO_RESOURCES;
UINT8 shld_enable = 0x01;
UINT8 enable_param[BTM_BLE_BATCH_SCAN_ENB_DISB_LEN], *pp_enable;
if (!should_enable) {
shld_enable = 0x00;
}
if (should_enable) {
pp_enable = enable_param;
memset(enable_param, 0, BTM_BLE_BATCH_SCAN_ENB_DISB_LEN);
UINT8_TO_STREAM (pp_enable, BTM_BLE_BATCH_SCAN_ENB_DISAB_CUST_FEATURE);
UINT8_TO_STREAM (pp_enable, shld_enable);
if ((status = BTM_VendorSpecificCommand(HCI_BLE_BATCH_SCAN_OCF,
BTM_BLE_BATCH_SCAN_ENB_DISB_LEN, enable_param,
btm_ble_batchscan_vsc_cmpl_cback)) != BTM_CMD_STARTED) {
status = BTM_MODE_UNSUPPORTED;
BTM_TRACE_ERROR("btm_ble_enable_disable_batchscan %d", status);
return BTM_ILLEGAL_VALUE;
}
} else if ((status = btm_ble_set_batchscan_param(BTM_BLE_BATCH_SCAN_MODE_DISABLE,
ble_batchscan_cb.scan_interval, ble_batchscan_cb.scan_window,
ble_batchscan_cb.addr_type, ble_batchscan_cb.discard_rule)) != BTM_CMD_STARTED) {
status = BTM_MODE_UNSUPPORTED;
BTM_TRACE_ERROR("btm_ble_enable_disable_batchscan %d", status);
return BTM_ILLEGAL_VALUE;
}
if (should_enable) {
ble_batchscan_cb.cur_state = BTM_BLE_SCAN_ENABLE_CALLED;
} else {
ble_batchscan_cb.cur_state = BTM_BLE_SCAN_DISABLE_CALLED;
}
return status;
}
/*******************************************************************************
**
** Function BTM_BleSetStorageConfig
**
** Description This function is called to write storage config params.
**
** Parameters: batch_scan_full_max - Max storage space (in %) allocated to full style
** batch_scan_trunc_max - Max storage space (in %) allocated to trunc style
** batch_scan_notify_threshold - Setup notification level based on total space
** p_setup_cback - Setup callback pointer
** p_thres_cback - Threshold callback pointer
** p_rep_cback - Reports callback pointer
** ref_value - Reference value
**
** Returns tBTM_STATUS
**
*******************************************************************************/
tBTM_STATUS BTM_BleSetStorageConfig(UINT8 batch_scan_full_max, UINT8 batch_scan_trunc_max,
UINT8 batch_scan_notify_threshold,
tBTM_BLE_SCAN_SETUP_CBACK *p_setup_cback,
tBTM_BLE_SCAN_THRESHOLD_CBACK *p_thres_cback,
tBTM_BLE_SCAN_REP_CBACK *p_rep_cback,
tBTM_BLE_REF_VALUE ref_value)
{
tBTM_STATUS status = BTM_NO_RESOURCES;
tBTM_BLE_VSC_CB cmn_ble_vsc_cb;
BTM_TRACE_EVENT (" BTM_BleSetStorageConfig: %d, %d, %d, %d, %d",
ble_batchscan_cb.cur_state, ref_value, batch_scan_full_max, batch_scan_trunc_max,
batch_scan_notify_threshold);
if (!controller_get_interface()->supports_ble()) {
return BTM_ILLEGAL_VALUE;
}
BTM_BleGetVendorCapabilities(&cmn_ble_vsc_cb);
if (0 == cmn_ble_vsc_cb.tot_scan_results_strg) {
BTM_TRACE_ERROR("Controller does not support batch scan");
return BTM_ERR_PROCESSING;
}
ble_batchscan_cb.p_setup_cback = p_setup_cback;
ble_batchscan_cb.p_thres_cback = p_thres_cback;
ble_batchscan_cb.p_scan_rep_cback = p_rep_cback;
ble_batchscan_cb.ref_value = ref_value;
if (batch_scan_full_max > BTM_BLE_ADV_SCAN_FULL_MAX ||
batch_scan_trunc_max > BTM_BLE_ADV_SCAN_TRUNC_MAX ||
batch_scan_notify_threshold > BTM_BLE_ADV_SCAN_THR_MAX) {
BTM_TRACE_ERROR("Illegal set storage config params");
return BTM_ILLEGAL_VALUE;
}
if (BTM_BLE_SCAN_INVALID_STATE == ble_batchscan_cb.cur_state ||
BTM_BLE_SCAN_DISABLED_STATE == ble_batchscan_cb.cur_state ||
BTM_BLE_SCAN_DISABLE_CALLED == ble_batchscan_cb.cur_state) {
status = btm_ble_enable_disable_batchscan(TRUE);
if (BTM_CMD_STARTED != status) {
return status;
}
ble_batchscan_cb.cur_state = BTM_BLE_SCAN_ENABLE_CALLED;
btm_ble_batchscan_enq_op_q(BTM_BLE_BATCH_SCAN_ENB_DISAB_CUST_FEATURE,
BTM_BLE_SCAN_ENABLE_CALLED, 0, ref_value);
}
status = btm_ble_set_storage_config(batch_scan_full_max, batch_scan_trunc_max,
batch_scan_notify_threshold);
if (BTM_CMD_STARTED != status) {
return status;
}
/* The user needs to be provided scan config storage event */
btm_ble_batchscan_enq_op_q(BTM_BLE_BATCH_SCAN_SET_STORAGE_PARAM, ble_batchscan_cb.cur_state,
BTM_BLE_BATCH_SCAN_CFG_STRG_EVT, ref_value);
return status;
}
/*******************************************************************************
**
** Function BTM_BleEnableBatchScan
**
** Description This function is called to configure and enable batch scanning
**
** Parameters: scan_mode -Batch scan mode
** scan_interval - Scan interval value
** scan_window - Scan window value
** discard_rule - Data discard rule
** ref_value - Reference value
**
** Returns tBTM_STATUS
**
*******************************************************************************/
tBTM_STATUS BTM_BleEnableBatchScan(tBTM_BLE_BATCH_SCAN_MODE scan_mode,
UINT32 scan_interval, UINT32 scan_window, tBLE_ADDR_TYPE addr_type,
tBTM_BLE_DISCARD_RULE discard_rule, tBTM_BLE_REF_VALUE ref_value)
{
tBTM_STATUS status = BTM_NO_RESOURCES;
tBTM_BLE_VSC_CB cmn_ble_vsc_cb;
BTM_TRACE_EVENT (" BTM_BleEnableBatchScan: %d, %d, %d, %d, %d, %d",
scan_mode, scan_interval, scan_window, addr_type, discard_rule, ref_value);
if (!controller_get_interface()->supports_ble()) {
return BTM_ILLEGAL_VALUE;
}
BTM_BleGetVendorCapabilities(&cmn_ble_vsc_cb);
if (0 == cmn_ble_vsc_cb.tot_scan_results_strg) {
BTM_TRACE_ERROR("Controller does not support batch scan");
return BTM_ERR_PROCESSING;
}
BTM_TRACE_DEBUG("BTM_BleEnableBatchScan: %d, %x, %x, %d, %d", scan_mode, scan_interval,
scan_window, discard_rule, ble_batchscan_cb.cur_state);
/* Only 16 bits will be used for scan interval and scan window as per agreement with Google */
/* So the standard LE range would suffice for scan interval and scan window */
if ((BTM_BLE_ISVALID_PARAM(scan_interval, BTM_BLE_SCAN_INT_MIN, BTM_BLE_SCAN_INT_MAX) ||
BTM_BLE_ISVALID_PARAM(scan_window, BTM_BLE_SCAN_WIN_MIN, BTM_BLE_SCAN_WIN_MAX))
&& (BTM_BLE_BATCH_SCAN_MODE_PASS == scan_mode || BTM_BLE_BATCH_SCAN_MODE_ACTI == scan_mode
|| BTM_BLE_BATCH_SCAN_MODE_PASS_ACTI == scan_mode)
&& (BTM_BLE_DISCARD_OLD_ITEMS == discard_rule ||
BTM_BLE_DISCARD_LOWER_RSSI_ITEMS == discard_rule)) {
if (BTM_BLE_SCAN_INVALID_STATE == ble_batchscan_cb.cur_state ||
BTM_BLE_SCAN_DISABLED_STATE == ble_batchscan_cb.cur_state ||
BTM_BLE_SCAN_DISABLE_CALLED == ble_batchscan_cb.cur_state) {
status = btm_ble_enable_disable_batchscan(TRUE);
if (BTM_CMD_STARTED != status) {
return status;
}
btm_ble_batchscan_enq_op_q(BTM_BLE_BATCH_SCAN_ENB_DISAB_CUST_FEATURE,
BTM_BLE_SCAN_ENABLE_CALLED, 0, ref_value);
}
ble_batchscan_cb.scan_mode = scan_mode;
ble_batchscan_cb.scan_interval = scan_interval;
ble_batchscan_cb.scan_window = scan_window;
ble_batchscan_cb.addr_type = addr_type;
ble_batchscan_cb.discard_rule = discard_rule;
/* This command starts batch scanning, if enabled */
status = btm_ble_set_batchscan_param(scan_mode, scan_interval, scan_window, addr_type,
discard_rule);
if (BTM_CMD_STARTED != status) {
return status;
}
/* The user needs to be provided scan enable event */
btm_ble_batchscan_enq_op_q(BTM_BLE_BATCH_SCAN_SET_PARAMS, ble_batchscan_cb.cur_state,
BTM_BLE_BATCH_SCAN_ENABLE_EVT, ref_value);
} else {
BTM_TRACE_ERROR("Illegal enable scan params");
return BTM_ILLEGAL_VALUE;
}
return status;
}
/*******************************************************************************
**
** Function BTM_BleDisableBatchScan
**
** Description This function is called to disable batch scanning
**
** Parameters: ref_value - Reference value
**
** Returns tBTM_STATUS
**
*******************************************************************************/
tBTM_STATUS BTM_BleDisableBatchScan(tBTM_BLE_REF_VALUE ref_value)
{
tBTM_STATUS status = BTM_NO_RESOURCES;
tBTM_BLE_VSC_CB cmn_ble_vsc_cb;
BTM_TRACE_EVENT (" BTM_BleDisableBatchScan");
if (!controller_get_interface()->supports_ble()) {
return BTM_ILLEGAL_VALUE;
}
BTM_BleGetVendorCapabilities(&cmn_ble_vsc_cb);
if (0 == cmn_ble_vsc_cb.tot_scan_results_strg) {
BTM_TRACE_ERROR("Controller does not support batch scan");
return BTM_ERR_PROCESSING;
}
status = btm_ble_enable_disable_batchscan(FALSE);
if (BTM_CMD_STARTED == status) {
/* The user needs to be provided scan disable event */
btm_ble_batchscan_enq_op_q(BTM_BLE_BATCH_SCAN_SET_PARAMS,
BTM_BLE_SCAN_DISABLE_CALLED, BTM_BLE_BATCH_SCAN_DISABLE_EVT,
ref_value);
}
return status;
}
/*******************************************************************************
**
** Function BTM_BleReadScanReports
**
** Description This function is called to start reading batch scan reports
**
** Parameters: scan_mode - Batch scan mode
** ref_value - Reference value
**
** Returns tBTM_STATUS
**
*******************************************************************************/
tBTM_STATUS BTM_BleReadScanReports(tBTM_BLE_BATCH_SCAN_MODE scan_mode,
tBTM_BLE_REF_VALUE ref_value)
{
tBTM_STATUS status = BTM_NO_RESOURCES;
tBTM_BLE_VSC_CB cmn_ble_vsc_cb;
UINT8 read_scan_mode = 0;
UINT8 *p_data = NULL, num_records = 0;
UINT16 data_len = 0;
BTM_TRACE_EVENT (" BTM_BleReadScanReports; %d, %d", scan_mode, ref_value);
if (!controller_get_interface()->supports_ble()) {
return BTM_ILLEGAL_VALUE;
}
BTM_BleGetVendorCapabilities(&cmn_ble_vsc_cb);
if (0 == cmn_ble_vsc_cb.tot_scan_results_strg) {
BTM_TRACE_ERROR("Controller does not support batch scan");
return BTM_ERR_PROCESSING;
}
/* Check if the requested scan mode has already been setup by the user */
read_scan_mode = ble_batchscan_cb.scan_mode & BTM_BLE_BATCH_SCAN_MODE_ACTI;
if (0 == read_scan_mode) {
read_scan_mode = ble_batchscan_cb.scan_mode & BTM_BLE_BATCH_SCAN_MODE_PASS;
}
/* Check only for modes, as scan reports can be called after disabling batch scan */
if (read_scan_mode > 0 && (BTM_BLE_BATCH_SCAN_MODE_PASS == scan_mode ||
BTM_BLE_BATCH_SCAN_MODE_ACTI == scan_mode)) {
status = btm_ble_batchscan_enq_rep_q(scan_mode, ref_value);
if (BTM_SUCCESS == status) {
status = btm_ble_read_batchscan_reports(scan_mode, ref_value);
if (BTM_CMD_STARTED != status) {
btm_ble_batchscan_deq_rep_data(scan_mode, &ref_value,
&num_records, &p_data, &data_len);
}
}
} else {
BTM_TRACE_ERROR("Illegal read scan params: %d, %d, %d", read_scan_mode, scan_mode,
ble_batchscan_cb.cur_state);
return BTM_ILLEGAL_VALUE;
}
return status;
}
/*******************************************************************************
**
** Function BTM_BleTrackAdvertiser
**
** Description This function is called to setup the callback for tracking advertisers
**
** Parameters: p_track_cback - Tracking callback pointer
** ref_value - Reference value
**
** Returns tBTM_STATUS
**
*******************************************************************************/
tBTM_STATUS BTM_BleTrackAdvertiser(tBTM_BLE_TRACK_ADV_CBACK *p_track_cback,
tBTM_BLE_REF_VALUE ref_value)
{
tBTM_BLE_VSC_CB cmn_ble_vsc_cb;
BTM_TRACE_EVENT (" BTM_BleTrackAdvertiser");
if (!controller_get_interface()->supports_ble()) {
return BTM_ILLEGAL_VALUE;
}
BTM_BleGetVendorCapabilities(&cmn_ble_vsc_cb);
if (0 == cmn_ble_vsc_cb.tot_scan_results_strg) {
BTM_TRACE_ERROR("Controller does not support scan storage");
return BTM_ERR_PROCESSING;
}
ble_advtrack_cb.p_track_cback = p_track_cback;
ble_advtrack_cb.ref_value = ref_value;
return BTM_CMD_STARTED;
}
/*******************************************************************************
**
** Function btm_ble_batchscan_init
**
** Description This function initialize the batch scan control block.
**
** Parameters None
**
** Returns status
**
*******************************************************************************/
void btm_ble_batchscan_init(void)
{
#if BTM_DYNAMIC_MEMORY == TRUE
ble_batchscan_cb_ptr = (tBTM_BLE_BATCH_SCAN_CB *)osi_malloc(sizeof(tBTM_BLE_BATCH_SCAN_CB));
ble_advtrack_cb_ptr = (tBTM_BLE_ADV_TRACK_CB *)osi_malloc(sizeof(tBTM_BLE_ADV_TRACK_CB));
if (ble_batchscan_cb_ptr == NULL || ble_advtrack_cb_ptr == NULL) {
BTM_TRACE_ERROR("%s malloc failed", __func__);
return;
}
#endif
BTM_TRACE_EVENT (" btm_ble_batchscan_init");
memset(&ble_batchscan_cb, 0, sizeof(tBTM_BLE_BATCH_SCAN_CB));
memset(&ble_advtrack_cb, 0, sizeof(tBTM_BLE_ADV_TRACK_CB));
BTM_RegisterForVSEvents(btm_ble_batchscan_filter_track_adv_vse_cback, TRUE);
}
/*******************************************************************************
**
** Function btm_ble_batchscan_cleanup
**
** Description This function cleans the batch scan control block.
**
** Parameters None
**
** Returns void
**
*******************************************************************************/
void btm_ble_batchscan_cleanup(void)
{
int index = 0;
BTM_TRACE_EVENT (" btm_ble_batchscan_cleanup");
for (index = 0; index < BTM_BLE_BATCH_REP_MAIN_Q_SIZE; index++) {
if (NULL != ble_batchscan_cb.main_rep_q.p_data[index]) {
osi_free(ble_batchscan_cb.main_rep_q.p_data[index]);
ble_batchscan_cb.main_rep_q.p_data[index] = NULL;
}
}
memset(&ble_batchscan_cb, 0, sizeof(tBTM_BLE_BATCH_SCAN_CB));
memset(&ble_advtrack_cb, 0, sizeof(tBTM_BLE_ADV_TRACK_CB));
#if BTM_DYNAMIC_MEMORY == TRUE
osi_free(ble_batchscan_cb_ptr);
osi_free(ble_advtrack_cb_ptr);
ble_batchscan_cb_ptr = NULL;
ble_advtrack_cb_ptr = NULL;
#endif
}
#endif
@@ -0,0 +1,836 @@
/******************************************************************************
*
* Copyright (C) 1999-2012 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.
*
******************************************************************************/
/******************************************************************************
*
* This file contains functions for BLE whitelist operation.
*
******************************************************************************/
#include <string.h>
#include "common/bt_trace.h"
#include "device/controller.h"
#include "osi/allocator.h"
#include "osi/hash_map.h"
#include "stack/bt_types.h"
#include "stack/btu.h"
#include "btm_int.h"
#include "l2c_int.h"
#include "stack/hcimsgs.h"
//#include "bt_utils.h"
#ifndef BTM_BLE_SCAN_PARAM_TOUT
#define BTM_BLE_SCAN_PARAM_TOUT 50 /* 50 seconds */
#endif
#if (BLE_INCLUDED == TRUE)
static void btm_suspend_wl_activity(tBTM_BLE_WL_STATE wl_state);
static void btm_wl_update_to_controller(void);
// Unfortunately (for now?) we have to maintain a copy of the device whitelist
// on the host to determine if a device is pending to be connected or not. This
// controls whether the host should keep trying to scan for whitelisted
// peripherals or not.
// TODO: Move all of this to controller/le/background_list or similar?
static const size_t background_connection_buckets = 42;
static hash_map_t *background_connections = NULL;
typedef struct background_connection_t {
bt_bdaddr_t address;
} background_connection_t;
static bool bdaddr_equality_fn(const void *x, const void *y)
{
return bdaddr_equals((bt_bdaddr_t *)x, (bt_bdaddr_t *)y);
}
static void background_connections_lazy_init(void)
{
if (!background_connections) {
background_connections = hash_map_new(background_connection_buckets,
hash_function_bdaddr, NULL, osi_free_func, bdaddr_equality_fn);
assert(background_connections);
}
}
static BOOLEAN background_connection_add(bt_bdaddr_t *address)
{
assert(address);
background_connections_lazy_init();
background_connection_t *connection = hash_map_get(background_connections, address);
if (!connection) {
connection = osi_calloc(sizeof(background_connection_t));
connection->address = *address;
hash_map_set(background_connections, &(connection->address), connection);
return TRUE;
}
return FALSE;
}
static BOOLEAN background_connection_remove(bt_bdaddr_t *address)
{
if (address && background_connections) {
return hash_map_erase(background_connections, address);
}
return FALSE;
}
static void background_connections_clear(void)
{
if (background_connections) {
hash_map_clear(background_connections);
}
}
static bool background_connections_pending_cb(hash_map_entry_t *hash_entry, void *context)
{
bool *pending_connections = context;
background_connection_t *connection = hash_entry->data;
const bool connected = BTM_IsAclConnectionUp(connection->address.address, BT_TRANSPORT_LE);
if (!connected) {
*pending_connections = true;
return false;
}
return true;
}
static bool background_connections_pending(void)
{
bool pending_connections = false;
if (background_connections) {
hash_map_foreach(background_connections, background_connections_pending_cb, &pending_connections);
}
return pending_connections;
}
/*******************************************************************************
**
** Function btm_update_scanner_filter_policy
**
** Description This function updates the filter policy of scanner
*******************************************************************************/
void btm_update_scanner_filter_policy(tBTM_BLE_SFP scan_policy)
{
tBTM_BLE_INQ_CB *p_inq = &btm_cb.ble_ctr_cb.inq_var;
UINT32 scan_interval = !p_inq->scan_interval ? BTM_BLE_GAP_DISC_SCAN_INT : p_inq->scan_interval;
UINT32 scan_window = !p_inq->scan_window ? BTM_BLE_GAP_DISC_SCAN_WIN : p_inq->scan_window;
BTM_TRACE_EVENT ("%s\n", __func__);
p_inq->sfp = scan_policy;
p_inq->scan_type = p_inq->scan_type == BTM_BLE_SCAN_MODE_NONE ? BTM_BLE_SCAN_MODE_ACTI : p_inq->scan_type;
if (btm_cb.cmn_ble_vsc_cb.extended_scan_support == 0) {
btsnd_hcic_ble_set_scan_params(p_inq->scan_type, (UINT16)scan_interval,
(UINT16)scan_window,
btm_cb.ble_ctr_cb.addr_mgnt_cb.own_addr_type,
scan_policy);
} else {
btm_ble_send_extended_scan_params(p_inq->scan_type, scan_interval, scan_window,
btm_cb.ble_ctr_cb.addr_mgnt_cb.own_addr_type,
scan_policy);
}
}
/*******************************************************************************
**
** Function btm_add_dev_to_controller
**
** Description This function load the device into controller white list
*******************************************************************************/
BOOLEAN btm_add_dev_to_controller (BOOLEAN to_add, BD_ADDR bd_addr, tBLE_ADDR_TYPE wl_addr_type)
{
/*
tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (bd_addr);
tBLE_ADDR_TYPE addr_type = BLE_ADDR_PUBLIC;
BOOLEAN started = FALSE;
BD_ADDR dummy_bda = {0};
tBT_DEVICE_TYPE dev_type;
if (p_dev_rec != NULL &&
p_dev_rec->device_type & BT_DEVICE_TYPE_BLE) {
if (to_add) {
if (p_dev_rec->ble.ble_addr_type == BLE_ADDR_PUBLIC || !BTM_BLE_IS_RESOLVE_BDA(bd_addr)) {
started = btsnd_hcic_ble_add_white_list (p_dev_rec->ble.ble_addr_type, bd_addr);
p_dev_rec->ble.in_controller_list |= BTM_WHITE_LIST_BIT;
} else if (memcmp(p_dev_rec->ble.static_addr, bd_addr, BD_ADDR_LEN) != 0 &&
memcmp(p_dev_rec->ble.static_addr, dummy_bda, BD_ADDR_LEN) != 0) {
started = btsnd_hcic_ble_add_white_list (p_dev_rec->ble.static_addr_type,
p_dev_rec->ble.static_addr);
p_dev_rec->ble.in_controller_list |= BTM_WHITE_LIST_BIT;
}
} else {
if (p_dev_rec->ble.ble_addr_type == BLE_ADDR_PUBLIC || !BTM_BLE_IS_RESOLVE_BDA(bd_addr)) {
started = btsnd_hcic_ble_remove_from_white_list (p_dev_rec->ble.ble_addr_type, bd_addr);
}
if (memcmp(p_dev_rec->ble.static_addr, dummy_bda, BD_ADDR_LEN) != 0 &&
memcmp(p_dev_rec->ble.static_addr, bd_addr, BD_ADDR_LEN) != 0) {
started = btsnd_hcic_ble_remove_from_white_list (p_dev_rec->ble.static_addr_type, p_dev_rec->ble.static_addr);
}
p_dev_rec->ble.in_controller_list &= ~BTM_WHITE_LIST_BIT;
}
} // if not a known device, shall we add it?
else {
BTM_ReadDevInfo(bd_addr, &dev_type, &addr_type);
if (to_add) {
started = btsnd_hcic_ble_add_white_list (addr_type, bd_addr);
}else{
started = btsnd_hcic_ble_remove_from_white_list (addr_type, bd_addr);
}
}
return started;
*/
/* Controller do not support resolvable address now, only support public address and static random address */
BOOLEAN started = FALSE;
if(wl_addr_type > BLE_ADDR_RANDOM) {
BTM_TRACE_ERROR("wl_addr_type is error\n");
return started;
}
if (to_add) {
started = btsnd_hcic_ble_add_white_list (wl_addr_type, bd_addr);
}else{
started = btsnd_hcic_ble_remove_from_white_list (wl_addr_type, bd_addr);
}
return started;
}
/*******************************************************************************
**
** Function btm_execute_wl_dev_operation
**
** Description execute the pending whitelist device operation(loading or removing)
*******************************************************************************/
BOOLEAN btm_execute_wl_dev_operation(void)
{
tBTM_BLE_WL_OP *p_dev_op = btm_cb.ble_ctr_cb.wl_op_q;
UINT8 i = 0;
BOOLEAN rt = TRUE;
for (i = 0; i < BTM_BLE_MAX_BG_CONN_DEV_NUM && rt; i ++, p_dev_op ++) {
if (p_dev_op->in_use) {
rt = btm_add_dev_to_controller(p_dev_op->to_add, p_dev_op->bd_addr, p_dev_op->addr_type);
memset(p_dev_op, 0, sizeof(tBTM_BLE_WL_OP));
} else {
break;
}
}
return rt;
}
/*******************************************************************************
**
** Function btm_enq_wl_dev_operation
**
** Description enqueue the pending whitelist device operation(loading or removing).
*******************************************************************************/
void btm_enq_wl_dev_operation(BOOLEAN to_add, BD_ADDR bd_addr, tBLE_ADDR_TYPE addr_type)
{
tBTM_BLE_WL_OP *p_dev_op = btm_cb.ble_ctr_cb.wl_op_q;
UINT8 i = 0;
for (i = 0; i < BTM_BLE_MAX_BG_CONN_DEV_NUM; i ++, p_dev_op ++) {
if (p_dev_op->in_use && p_dev_op->addr_type == addr_type && !memcmp(p_dev_op->bd_addr, bd_addr, BD_ADDR_LEN)) {
p_dev_op->to_add = to_add;
return;
} else if (!p_dev_op->in_use) {
break;
}
}
if (i != BTM_BLE_MAX_BG_CONN_DEV_NUM) {
p_dev_op->in_use = TRUE;
p_dev_op->to_add = to_add;
p_dev_op->addr_type = addr_type;
memcpy(p_dev_op->bd_addr, bd_addr, BD_ADDR_LEN);
} else {
BTM_TRACE_ERROR("max pending WL operation reached, discard");
}
return;
}
/*******************************************************************************
**
** Function btm_update_dev_to_white_list
**
** Description This function adds or removes a device into/from
** the white list.
**
*******************************************************************************/
BOOLEAN btm_update_dev_to_white_list(BOOLEAN to_add, BD_ADDR bd_addr, tBLE_ADDR_TYPE addr_type, tBTM_UPDATE_WHITELIST_CBACK *update_wl_cb)
{
if(addr_type > BLE_ADDR_RANDOM) {
BTM_TRACE_ERROR("%s address type is error, unable to add device", __func__);
if (update_wl_cb){
update_wl_cb(HCI_ERR_ILLEGAL_PARAMETER_FMT,to_add);
}
return FALSE;
}
BD_ADDR invalid_rand_addr_a, invalid_rand_addr_b;
memset(invalid_rand_addr_a, 0xff, sizeof(BD_ADDR));
memset(invalid_rand_addr_b, 0x00, sizeof(BD_ADDR));
// look for public address information
tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev(bd_addr);
// p_dev_rec is created at bluetooth initialization, p_dev_rec->ble.static_addr maybe be all 0 before pairing
if(p_dev_rec && memcmp(invalid_rand_addr_b, p_dev_rec->ble.static_addr, BD_ADDR_LEN) != 0) {
memcpy(bd_addr, p_dev_rec->ble.static_addr, BD_ADDR_LEN);
addr_type = p_dev_rec->ble.static_addr_type;
}
// The device to be added to white list must be public address or random address
if(addr_type == BLE_ADDR_RANDOM) {
/*
A static address is a 48-bit randomly generated address and shall meet the following requirements:
• The two most significant bits of the address shall be equal to 1
• All bits of the random part of the address shall not be equal to 1
• All bits of the random part of the address shall not be equal to 0
*/
invalid_rand_addr_b[0] = invalid_rand_addr_b[0] | BT_STATIC_RAND_ADDR_MASK;
if(memcmp(invalid_rand_addr_a, bd_addr, BD_ADDR_LEN) != 0
&& memcmp(invalid_rand_addr_b, bd_addr, BD_ADDR_LEN) != 0){
// do nothing
} else {
BTC_TRACE_ERROR(" controller not support resolvable address");
if (update_wl_cb){
update_wl_cb(HCI_ERR_ILLEGAL_PARAMETER_FMT,to_add);
}
return FALSE;
}
}
tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb;
if (to_add && p_cb->white_list_avail_size == 0) {
BTM_TRACE_ERROR("%s Whitelist full, unable to add device", __func__);
if (update_wl_cb){
update_wl_cb(HCI_ERR_MEMORY_FULL,to_add);
}
return FALSE;
}
if (to_add) {
/* added the bd_addr to the connection hash map queue */
if(!background_connection_add((bt_bdaddr_t *)bd_addr)) {
/* if the bd_addr already exist in whitelist, just callback return TRUE */
if (update_wl_cb){
update_wl_cb(HCI_SUCCESS,to_add);
}
return TRUE;
}
} else {
/* remove the bd_addr to the connection hash map queue */
if(!background_connection_remove((bt_bdaddr_t *)bd_addr)){
/* if the bd_addr don't exist in whitelist, just callback return TRUE */
if (update_wl_cb){
update_wl_cb(HCI_SUCCESS,to_add);
}
return TRUE;
}
}
if (update_wl_cb){
//save add whitelist complete callback
p_cb->update_wl_cb = update_wl_cb;
}
/* stop the auto connect */
btm_suspend_wl_activity(p_cb->wl_state);
/* save the bd_addr to the btm_cb env */
btm_enq_wl_dev_operation(to_add, bd_addr, addr_type);
/* save the ba_addr to the controller white list */
btm_wl_update_to_controller();
return TRUE;
}
/*******************************************************************************
**
** Function btm_ble_clear_white_list
**
** Description This function clears the white list.
**
*******************************************************************************/
void btm_ble_clear_white_list (tBTM_UPDATE_WHITELIST_CBACK *update_wl_cb)
{
tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb;
BTM_TRACE_EVENT ("btm_ble_clear_white_list");
btsnd_hcic_ble_clear_white_list();
background_connections_clear();
if (update_wl_cb) {
p_cb->update_wl_cb = update_wl_cb;
}
}
/*******************************************************************************
**
** Function btm_ble_clear_white_list_complete
**
** Description Indicates white list cleared.
**
*******************************************************************************/
void btm_ble_clear_white_list_complete(UINT8 *p_data, UINT16 evt_len)
{
tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb;
UINT8 status;
UNUSED(evt_len);
BTM_TRACE_EVENT ("btm_ble_clear_white_list_complete");
STREAM_TO_UINT8 (status, p_data);
if (status == HCI_SUCCESS) {
p_cb->white_list_avail_size = controller_get_interface()->get_ble_white_list_size();
} else {
BTM_TRACE_ERROR ("%s failed, status 0x%x\n", __func__, status);
}
if (p_cb->update_wl_cb) {
(*p_cb->update_wl_cb)(status, BTM_WHITELIST_CLEAR);
}
}
/*******************************************************************************
**
** Function btm_ble_white_list_init
**
** Description Initialize white list size
**
*******************************************************************************/
void btm_ble_white_list_init(UINT8 white_list_size)
{
BTM_TRACE_DEBUG("%s white_list_size = %d", __func__, white_list_size);
btm_cb.ble_ctr_cb.white_list_avail_size = white_list_size;
}
/*******************************************************************************
**
** Function btm_ble_add_2_white_list_complete
**
** Description White list element added
**
*******************************************************************************/
void btm_ble_add_2_white_list_complete(UINT8 status)
{
BTM_TRACE_EVENT("%s status=%d", __func__, status);
tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb;
if (status == HCI_SUCCESS) {
--btm_cb.ble_ctr_cb.white_list_avail_size;
}
// add whitelist complete callback
if (p_cb->update_wl_cb)
{
(*p_cb->update_wl_cb)(status, BTM_WHITELIST_ADD);
}
}
/*******************************************************************************
**
** Function btm_ble_remove_from_white_list_complete
**
** Description White list element removal complete
**
*******************************************************************************/
void btm_ble_remove_from_white_list_complete(UINT8 *p, UINT16 evt_len)
{
tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb;
UNUSED(evt_len);
BTM_TRACE_EVENT ("%s status=%d", __func__, *p);
if (*p == HCI_SUCCESS) {
++btm_cb.ble_ctr_cb.white_list_avail_size;
}
if (p_cb->update_wl_cb)
{
(*p_cb->update_wl_cb)(*p, BTM_WHITELIST_REMOVE);
}
}
/*******************************************************************************
**
** Function btm_ble_start_auto_conn
**
** Description This function is to start/stop auto connection procedure.
**
** Parameters start: TRUE to start; FALSE to stop.
**
** Returns void
**
*******************************************************************************/
BOOLEAN btm_ble_start_auto_conn(BOOLEAN start)
{
tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb;
BD_ADDR dummy_bda = {0};
BOOLEAN exec = TRUE;
UINT16 scan_int;
UINT16 scan_win;
UINT8 own_addr_type = p_cb->addr_mgnt_cb.own_addr_type;
UINT8 peer_addr_type = BLE_ADDR_PUBLIC;
if (start) {
if (p_cb->conn_state == BLE_CONN_IDLE && background_connections_pending()
&& btm_ble_topology_check(BTM_BLE_STATE_INIT)) {
p_cb->wl_state |= BTM_BLE_WL_INIT;
btm_execute_wl_dev_operation();
#if BLE_PRIVACY_SPT == TRUE
btm_ble_enable_resolving_list_for_platform(BTM_BLE_RL_INIT);
#endif
scan_int = (p_cb->scan_int == BTM_BLE_SCAN_PARAM_UNDEF) ?
BTM_BLE_SCAN_SLOW_INT_1 : p_cb->scan_int;
scan_win = (p_cb->scan_win == BTM_BLE_SCAN_PARAM_UNDEF) ?
BTM_BLE_SCAN_SLOW_WIN_1 : p_cb->scan_win;
#if BLE_PRIVACY_SPT == TRUE
if (btm_cb.ble_ctr_cb.rl_state != BTM_BLE_RL_IDLE
&& controller_get_interface()->supports_ble_privacy()) {
own_addr_type |= BLE_ADDR_TYPE_ID_BIT;
peer_addr_type |= BLE_ADDR_TYPE_ID_BIT;
}
#endif
if (!btsnd_hcic_ble_create_ll_conn (scan_int, /* UINT16 scan_int */
scan_win, /* UINT16 scan_win */
0x01, /* UINT8 white_list */
peer_addr_type, /* UINT8 addr_type_peer */
dummy_bda, /* BD_ADDR bda_peer */
own_addr_type, /* UINT8 addr_type_own */
BTM_BLE_CONN_INT_MIN_DEF, /* UINT16 conn_int_min */
BTM_BLE_CONN_INT_MAX_DEF, /* UINT16 conn_int_max */
BTM_BLE_CONN_SLAVE_LATENCY_DEF, /* UINT16 conn_latency */
BTM_BLE_CONN_TIMEOUT_DEF, /* UINT16 conn_timeout */
0, /* UINT16 min_len */
0)) { /* UINT16 max_len */
/* start auto connection failed */
exec = FALSE;
p_cb->wl_state &= ~BTM_BLE_WL_INIT;
} else {
btm_ble_set_conn_st (BLE_BG_CONN);
}
} else {
exec = FALSE;
}
} else {
if (p_cb->conn_state == BLE_BG_CONN) {
btsnd_hcic_ble_create_conn_cancel();
btm_ble_set_conn_st (BLE_CONN_CANCEL);
p_cb->wl_state &= ~BTM_BLE_WL_INIT;
} else {
BTM_TRACE_DEBUG("conn_st = %d, not in auto conn state, cannot stop", p_cb->conn_state);
exec = FALSE;
}
}
return exec;
}
/*******************************************************************************
**
** Function btm_ble_start_select_conn
**
** Description This function is to start/stop selective connection procedure.
**
** Parameters start: TRUE to start; FALSE to stop.
** p_select_cback: callback function to return application
** selection.
**
** Returns BOOLEAN: selective connection procedure is started.
**
*******************************************************************************/
BOOLEAN btm_ble_start_select_conn(BOOLEAN start, tBTM_BLE_SEL_CBACK *p_select_cback)
{
tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb;
UINT32 scan_int = p_cb->scan_int == BTM_BLE_SCAN_PARAM_UNDEF ? BTM_BLE_SCAN_FAST_INT : p_cb->scan_int;
UINT32 scan_win = p_cb->scan_win == BTM_BLE_SCAN_PARAM_UNDEF ? BTM_BLE_SCAN_FAST_WIN : p_cb->scan_win;
BTM_TRACE_EVENT ("%s", __func__);
if (start) {
if (!BTM_BLE_IS_SCAN_ACTIVE(p_cb->scan_activity)) {
if (p_select_cback != NULL) {
btm_cb.ble_ctr_cb.p_select_cback = p_select_cback;
}
btm_execute_wl_dev_operation();
btm_update_scanner_filter_policy(SP_ADV_WL);
btm_cb.ble_ctr_cb.inq_var.scan_type = BTM_BLE_SCAN_MODE_PASS;
/* Process advertising packets only from devices in the white list */
if (btm_cb.cmn_ble_vsc_cb.extended_scan_support == 0) {
/* use passive scan by default */
if (!btsnd_hcic_ble_set_scan_params(BTM_BLE_SCAN_MODE_PASS,
scan_int,
scan_win,
p_cb->addr_mgnt_cb.own_addr_type,
SP_ADV_WL)) {
return FALSE;
}
} else {
if (!btm_ble_send_extended_scan_params(BTM_BLE_SCAN_MODE_PASS,
scan_int,
scan_win,
p_cb->addr_mgnt_cb.own_addr_type,
SP_ADV_WL)) {
return FALSE;
}
}
if (!btm_ble_topology_check(BTM_BLE_STATE_PASSIVE_SCAN)) {
BTM_TRACE_ERROR("peripheral device cannot initiate passive scan for a selective connection");
return FALSE;
} else if (background_connections_pending()) {
#if BLE_PRIVACY_SPT == TRUE
btm_ble_enable_resolving_list_for_platform(BTM_BLE_RL_SCAN);
#endif
if (!btsnd_hcic_ble_set_scan_enable(TRUE, TRUE)) { /* duplicate filtering enabled */
return FALSE;
}
/* mark up inquiry status flag */
p_cb->scan_activity |= BTM_LE_SELECT_CONN_ACTIVE;
p_cb->wl_state |= BTM_BLE_WL_SCAN;
}
} else {
BTM_TRACE_ERROR("scan active, can not start selective connection procedure");
return FALSE;
}
} else { /* disable selective connection mode */
p_cb->scan_activity &= ~BTM_LE_SELECT_CONN_ACTIVE;
p_cb->p_select_cback = NULL;
p_cb->wl_state &= ~BTM_BLE_WL_SCAN;
/* stop scanning */
if (!BTM_BLE_IS_SCAN_ACTIVE(p_cb->scan_activity)) {
btm_ble_stop_scan(); /* duplicate filtering enabled */
}
}
return TRUE;
}
/*******************************************************************************
**
** Function btm_ble_initiate_select_conn
**
** Description This function is to start/stop selective connection procedure.
**
** Parameters start: TRUE to start; FALSE to stop.
** p_select_cback: callback function to return application
** selection.
**
** Returns BOOLEAN: selective connection procedure is started.
**
*******************************************************************************/
void btm_ble_initiate_select_conn(BD_ADDR bda)
{
BTM_TRACE_EVENT ("btm_ble_initiate_select_conn");
/* use direct connection procedure to initiate connection */
if (!L2CA_ConnectFixedChnl(L2CAP_ATT_CID, bda, BLE_ADDR_UNKNOWN_TYPE, FALSE)) {
BTM_TRACE_ERROR("btm_ble_initiate_select_conn failed");
}
}
/*******************************************************************************
**
** Function btm_ble_suspend_bg_conn
**
** Description This function is to suspend an active background connection
** procedure.
**
** Parameters none.
**
** Returns none.
**
*******************************************************************************/
BOOLEAN btm_ble_suspend_bg_conn(void)
{
BTM_TRACE_EVENT ("%s\n", __func__);
if (btm_cb.ble_ctr_cb.bg_conn_type == BTM_BLE_CONN_AUTO) {
return btm_ble_start_auto_conn(FALSE);
} else if (btm_cb.ble_ctr_cb.bg_conn_type == BTM_BLE_CONN_SELECTIVE) {
return btm_ble_start_select_conn(FALSE, NULL);
}
return FALSE;
}
/*******************************************************************************
**
** Function btm_suspend_wl_activity
**
** Description This function is to suspend white list related activity
**
** Returns none.
**
*******************************************************************************/
static void btm_suspend_wl_activity(tBTM_BLE_WL_STATE wl_state)
{
if (wl_state & BTM_BLE_WL_INIT) {
btm_ble_start_auto_conn(FALSE);
}
if (wl_state & BTM_BLE_WL_SCAN) {
btm_ble_start_select_conn(FALSE, NULL);
}
if (wl_state & BTM_BLE_WL_ADV) {
btm_ble_stop_adv();
}
}
/*******************************************************************************
**
** Function btm_resume_wl_activity
**
** Description This function is to resume white list related activity
**
** Returns none.
**
*******************************************************************************/
void btm_resume_wl_activity(tBTM_BLE_WL_STATE wl_state)
{
btm_ble_resume_bg_conn();
if (wl_state & BTM_BLE_WL_ADV) {
btm_ble_start_adv();
}
}
/*******************************************************************************
**
** Function btm_wl_update_to_controller
**
** Description This function is to update white list to controller
**
** Returns none.
**
*******************************************************************************/
static void btm_wl_update_to_controller(void)
{
/* whitelist will be added in the btm_ble_resume_bg_conn(), we do not
support background connection now, so we nedd to use btm_execute_wl_dev_operation
to add whitelist directly ,if we support background connection in the future,
please delete btm_execute_wl_dev_operation(). */
btm_execute_wl_dev_operation();
}
/*******************************************************************************
**
** Function btm_ble_resume_bg_conn
**
** Description This function is to resume a background auto connection
** procedure.
**
** Parameters none.
**
** Returns none.
**
*******************************************************************************/
BOOLEAN btm_ble_resume_bg_conn(void)
{
tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb;
BOOLEAN ret = FALSE;
if (p_cb->bg_conn_type != BTM_BLE_CONN_NONE) {
if (p_cb->bg_conn_type == BTM_BLE_CONN_AUTO) {
ret = btm_ble_start_auto_conn(TRUE);
}
if (p_cb->bg_conn_type == BTM_BLE_CONN_SELECTIVE) {
ret = btm_ble_start_select_conn(TRUE, btm_cb.ble_ctr_cb.p_select_cback);
}
}
return ret;
}
/*******************************************************************************
**
** Function btm_ble_get_conn_st
**
** Description This function get BLE connection state
**
** Returns connection state
**
*******************************************************************************/
tBTM_BLE_CONN_ST btm_ble_get_conn_st(void)
{
return btm_cb.ble_ctr_cb.conn_state;
}
/*******************************************************************************
**
** Function btm_ble_set_conn_st
**
** Description This function set BLE connection state
**
** Returns None.
**
*******************************************************************************/
void btm_ble_set_conn_st(tBTM_BLE_CONN_ST new_st)
{
btm_cb.ble_ctr_cb.conn_state = new_st;
if (new_st == BLE_BG_CONN || new_st == BLE_DIR_CONN) {
btm_ble_set_topology_mask(BTM_BLE_STATE_INIT_BIT);
} else {
btm_ble_clear_topology_mask(BTM_BLE_STATE_INIT_BIT);
}
}
/*******************************************************************************
**
** Function btm_ble_enqueue_direct_conn_req
**
** Description This function enqueue the direct connection request
**
** Returns None.
**
*******************************************************************************/
void btm_ble_enqueue_direct_conn_req(void *p_param)
{
tBTM_BLE_CONN_REQ *p = (tBTM_BLE_CONN_REQ *)osi_malloc(sizeof(tBTM_BLE_CONN_REQ));
p->p_param = p_param;
fixed_queue_enqueue(btm_cb.ble_ctr_cb.conn_pending_q, p, FIXED_QUEUE_MAX_TIMEOUT);
}
/*******************************************************************************
**
** Function btm_send_pending_direct_conn
**
** Description This function send the pending direct connection request in queue
**
** Returns TRUE if started, FALSE otherwise
**
*******************************************************************************/
BOOLEAN btm_send_pending_direct_conn(void)
{
tBTM_BLE_CONN_REQ *p_req;
BOOLEAN rt = FALSE;
p_req = (tBTM_BLE_CONN_REQ*)fixed_queue_dequeue(btm_cb.ble_ctr_cb.conn_pending_q, 0);
if (p_req != NULL) {
rt = l2cble_init_direct_conn((tL2C_LCB *)(p_req->p_param));
osi_free((void *)p_req);
}
return rt;
}
#endif
@@ -0,0 +1,108 @@
/******************************************************************************
*
* 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.
*
******************************************************************************/
#include <string.h>
#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 "bt_utils.h"
#include "stack/hcidefs.h"
#include "stack/btm_ble_api.h"
tBTM_BLE_ENERGY_INFO_CB ble_energy_info_cb;
/*******************************************************************************
**
** Function btm_ble_cont_energy_cmpl_cback
**
** Description Controller VSC complete callback
**
** Parameters
**
** Returns void
**
*******************************************************************************/
void btm_ble_cont_energy_cmpl_cback (tBTM_VSC_CMPL *p_params)
{
UINT8 *p = p_params->p_param_buf;
UINT16 len = p_params->param_len;
UINT8 status = 0;
UINT32 total_tx_time = 0, total_rx_time = 0, total_idle_time = 0, total_energy_used = 0;
if (len < 17) {
BTM_TRACE_ERROR("wrong length for btm_ble_cont_energy_cmpl_cback");
return;
}
STREAM_TO_UINT8(status, p);
STREAM_TO_UINT32(total_tx_time, p);
STREAM_TO_UINT32(total_rx_time, p);
STREAM_TO_UINT32(total_idle_time, p);
STREAM_TO_UINT32(total_energy_used, p);
BTM_TRACE_DEBUG("energy_info status=%d,tx_t=%u, rx_t=%u, ener_used=%u, idle_t=%u",
status, total_tx_time, total_rx_time, total_energy_used, total_idle_time);
if (NULL != ble_energy_info_cb.p_ener_cback) {
ble_energy_info_cb.p_ener_cback(total_tx_time, total_rx_time, total_idle_time,
total_energy_used, status);
}
return;
}
/*******************************************************************************
**
** Function BTM_BleGetEnergyInfo
**
** Description This function obtains the energy info
**
** Parameters p_ener_cback - Callback pointer
**
** Returns status
**
*******************************************************************************/
tBTM_STATUS BTM_BleGetEnergyInfo(tBTM_BLE_ENERGY_INFO_CBACK *p_ener_cback)
{
tBTM_STATUS status = BTM_ILLEGAL_VALUE;
tBTM_BLE_VSC_CB cmn_ble_vsc_cb;
BTM_BleGetVendorCapabilities(&cmn_ble_vsc_cb);
BTM_TRACE_EVENT("BTM_BleGetEnergyInfo\n");
if (0 == cmn_ble_vsc_cb.energy_support) {
BTM_TRACE_ERROR("Controller does not support get energy info\n");
return BTM_ERR_PROCESSING;
}
ble_energy_info_cb.p_ener_cback = p_ener_cback;
if ((status = BTM_VendorSpecificCommand (HCI_BLE_ENERGY_INFO_OCF, 0, NULL,
btm_ble_cont_energy_cmpl_cback)) != BTM_CMD_STARTED) {
BTM_TRACE_ERROR("BTM_BleGetEnergyInfo status: %d", status);
return BTM_ILLEGAL_VALUE;
}
return status;
}
#endif
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,878 @@
/******************************************************************************
*
* 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.
*
******************************************************************************/
#include <string.h>
#include "common/bt_target.h"
#include "device/controller.h"
#if (BLE_INCLUDED == TRUE)
#include "stack/bt_types.h"
#include "stack/hcimsgs.h"
#include "stack/btu.h"
#include "btm_int.h"
//#include "bt_utils.h"
#include "stack/hcidefs.h"
#include "stack/btm_ble_api.h"
/************************************************************************************
** Constants & Macros
************************************************************************************/
/* length of each multi adv sub command */
#define BTM_BLE_MULTI_ADV_ENB_LEN 3
#define BTM_BLE_MULTI_ADV_SET_PARAM_LEN 24
#define BTM_BLE_MULTI_ADV_WRITE_DATA_LEN (BTM_BLE_AD_DATA_LEN + 3)
#define BTM_BLE_MULTI_ADV_SET_RANDOM_ADDR_LEN 8
#define BTM_BLE_MULTI_ADV_CB_EVT_MASK 0xF0
#define BTM_BLE_MULTI_ADV_SUBCODE_MASK 0x0F
/************************************************************************************
** Static variables
************************************************************************************/
#if BTM_DYNAMIC_MEMORY == FALSE
tBTM_BLE_MULTI_ADV_CB btm_multi_adv_cb;
tBTM_BLE_MULTI_ADV_INST_IDX_Q btm_multi_adv_idx_q;
#else
tBTM_BLE_MULTI_ADV_CB *btm_multi_adv_cb_ptr;
tBTM_BLE_MULTI_ADV_INST_IDX_Q *btm_multi_adv_idx_q_ptr;
#define btm_multi_adv_cb (*btm_multi_adv_cb_ptr)
#define btm_multi_adv_idx_q (*btm_multi_adv_idx_q_ptr)
#endif
/************************************************************************************
** Externs
************************************************************************************/
extern void btm_ble_update_dmt_flag_bits(UINT8 *flag_value,
const UINT16 connect_mode, const UINT16 disc_mode);
/*******************************************************************************
**
** Function btm_ble_multi_adv_enq_op_q
**
** Description enqueue a multi adv operation in q to check command complete
** status.
**
** Returns void
**
*******************************************************************************/
void btm_ble_multi_adv_enq_op_q(UINT8 opcode, UINT8 inst_id, UINT8 cb_evt)
{
tBTM_BLE_MULTI_ADV_OPQ *p_op_q = &btm_multi_adv_cb.op_q;
p_op_q->p_inst_id[p_op_q->next_idx] = inst_id;
p_op_q->p_sub_code[p_op_q->next_idx] = (opcode | (cb_evt << 4));
p_op_q->next_idx = (p_op_q->next_idx + 1) % BTM_BleMaxMultiAdvInstanceCount();
}
/*******************************************************************************
**
** Function btm_ble_multi_adv_deq_op_q
**
** Description dequeue a multi adv operation from q when command complete
** is received.
**
** Returns void
**
*******************************************************************************/
void btm_ble_multi_adv_deq_op_q(UINT8 *p_opcode, UINT8 *p_inst_id, UINT8 *p_cb_evt)
{
tBTM_BLE_MULTI_ADV_OPQ *p_op_q = &btm_multi_adv_cb.op_q;
*p_inst_id = p_op_q->p_inst_id[p_op_q->pending_idx] & 0x7F;
*p_cb_evt = (p_op_q->p_sub_code[p_op_q->pending_idx] >> 4);
*p_opcode = (p_op_q->p_sub_code[p_op_q->pending_idx] & BTM_BLE_MULTI_ADV_SUBCODE_MASK);
p_op_q->pending_idx = (p_op_q->pending_idx + 1) % BTM_BleMaxMultiAdvInstanceCount();
}
/*******************************************************************************
**
** Function btm_ble_multi_adv_vsc_cmpl_cback
**
** Description Multi adv VSC complete callback
**
** Parameters
**
** Returns void
**
*******************************************************************************/
void btm_ble_multi_adv_vsc_cmpl_cback (tBTM_VSC_CMPL *p_params)
{
UINT8 status, subcode;
UINT8 *p = p_params->p_param_buf, inst_id;
UINT16 len = p_params->param_len;
tBTM_BLE_MULTI_ADV_INST *p_inst ;
UINT8 cb_evt = 0, opcode;
if (len < 2) {
BTM_TRACE_ERROR("wrong length for btm_ble_multi_adv_vsc_cmpl_cback");
return;
}
STREAM_TO_UINT8(status, p);
STREAM_TO_UINT8(subcode, p);
btm_ble_multi_adv_deq_op_q(&opcode, &inst_id, &cb_evt);
BTM_TRACE_DEBUG("op_code = %02x inst_id = %d cb_evt = %02x", opcode, inst_id, cb_evt);
if (opcode != subcode || inst_id == 0) {
BTM_TRACE_ERROR("get unexpected VSC cmpl, expect: %d get: %d", subcode, opcode);
return;
}
p_inst = &btm_multi_adv_cb.p_adv_inst[inst_id - 1];
switch (subcode) {
case BTM_BLE_MULTI_ADV_ENB: {
BTM_TRACE_DEBUG("BTM_BLE_MULTI_ADV_ENB status = %d", status);
/* Mark as not in use here, if instance cannot be enabled */
if (HCI_SUCCESS != status && BTM_BLE_MULTI_ADV_ENB_EVT == cb_evt) {
btm_multi_adv_cb.p_adv_inst[inst_id - 1].in_use = FALSE;
}
break;
}
case BTM_BLE_MULTI_ADV_SET_PARAM: {
BTM_TRACE_DEBUG("BTM_BLE_MULTI_ADV_SET_PARAM status = %d", status);
break;
}
case BTM_BLE_MULTI_ADV_WRITE_ADV_DATA: {
BTM_TRACE_DEBUG("BTM_BLE_MULTI_ADV_WRITE_ADV_DATA status = %d", status);
break;
}
case BTM_BLE_MULTI_ADV_WRITE_SCAN_RSP_DATA: {
BTM_TRACE_DEBUG("BTM_BLE_MULTI_ADV_WRITE_SCAN_RSP_DATA status = %d", status);
break;
}
case BTM_BLE_MULTI_ADV_SET_RANDOM_ADDR: {
BTM_TRACE_DEBUG("BTM_BLE_MULTI_ADV_SET_RANDOM_ADDR status = %d", status);
break;
}
default:
break;
}
if (cb_evt != 0 && p_inst->p_cback != NULL) {
(p_inst->p_cback)(cb_evt, inst_id, p_inst->p_ref, status);
}
return;
}
/*******************************************************************************
**
** Function btm_ble_enable_multi_adv
**
** Description This function enable the customer specific feature in controller
**
** Parameters enable: enable or disable
** inst_id: adv instance ID, can not be 0
**
** Returns status
**
*******************************************************************************/
tBTM_STATUS btm_ble_enable_multi_adv (BOOLEAN enable, UINT8 inst_id, UINT8 cb_evt)
{
UINT8 param[BTM_BLE_MULTI_ADV_ENB_LEN], *pp;
UINT8 enb = enable ? 1 : 0;
tBTM_STATUS rt;
pp = param;
memset(param, 0, BTM_BLE_MULTI_ADV_ENB_LEN);
UINT8_TO_STREAM (pp, BTM_BLE_MULTI_ADV_ENB);
UINT8_TO_STREAM (pp, enb);
UINT8_TO_STREAM (pp, inst_id);
BTM_TRACE_EVENT (" btm_ble_enable_multi_adv: enb %d, Inst ID %d", enb, inst_id);
if ((rt = BTM_VendorSpecificCommand (HCI_BLE_MULTI_ADV_OCF,
BTM_BLE_MULTI_ADV_ENB_LEN,
param,
btm_ble_multi_adv_vsc_cmpl_cback))
== BTM_CMD_STARTED) {
btm_ble_multi_adv_enq_op_q(BTM_BLE_MULTI_ADV_ENB, inst_id, cb_evt);
}
return rt;
}
/*******************************************************************************
**
** Function btm_ble_map_adv_tx_power
**
** Description return the actual power in dBm based on the mapping in config file
**
** Parameters advertise parameters used for this instance.
**
** Returns tx power in dBm
**
*******************************************************************************/
static const int btm_ble_tx_power[BTM_BLE_ADV_TX_POWER_MAX + 1] = BTM_BLE_ADV_TX_POWER;
char btm_ble_map_adv_tx_power(int tx_power_index)
{
if (0 <= tx_power_index && tx_power_index <= BTM_BLE_ADV_TX_POWER_MAX) {
return (char)btm_ble_tx_power[tx_power_index];
}
return 0;
}
/*******************************************************************************
**
** Function btm_ble_multi_adv_set_params
**
** Description This function enable the customer specific feature in controller
**
** Parameters advertise parameters used for this instance.
**
** Returns status
**
*******************************************************************************/
tBTM_STATUS btm_ble_multi_adv_set_params (tBTM_BLE_MULTI_ADV_INST *p_inst,
tBTM_BLE_ADV_PARAMS *p_params,
UINT8 cb_evt)
{
UINT8 param[BTM_BLE_MULTI_ADV_SET_PARAM_LEN], *pp;
tBTM_STATUS rt;
BD_ADDR dummy = {0, 0, 0, 0, 0, 0};
pp = param;
memset(param, 0, BTM_BLE_MULTI_ADV_SET_PARAM_LEN);
UINT8_TO_STREAM(pp, BTM_BLE_MULTI_ADV_SET_PARAM);
UINT16_TO_STREAM (pp, p_params->adv_int_min);
UINT16_TO_STREAM (pp, p_params->adv_int_max);
UINT8_TO_STREAM (pp, p_params->adv_type);
#if (defined BLE_PRIVACY_SPT && BLE_PRIVACY_SPT == TRUE)
if (btm_cb.ble_ctr_cb.privacy_mode != BTM_PRIVACY_NONE) {
UINT8_TO_STREAM (pp, BLE_ADDR_RANDOM);
BDADDR_TO_STREAM (pp, p_inst->rpa);
} else
#endif
{
UINT8_TO_STREAM (pp, BLE_ADDR_PUBLIC);
BDADDR_TO_STREAM (pp, controller_get_interface()->get_address()->address);
}
BTM_TRACE_EVENT (" btm_ble_multi_adv_set_params,Min %d, Max %d,adv_type %d",
p_params->adv_int_min, p_params->adv_int_max, p_params->adv_type);
UINT8_TO_STREAM (pp, 0);
BDADDR_TO_STREAM (pp, dummy);
if (p_params->channel_map == 0 || p_params->channel_map > BTM_BLE_DEFAULT_ADV_CHNL_MAP) {
p_params->channel_map = BTM_BLE_DEFAULT_ADV_CHNL_MAP;
}
UINT8_TO_STREAM (pp, p_params->channel_map);
if (p_params->adv_filter_policy >= AP_SCAN_CONN_POLICY_MAX) {
p_params->adv_filter_policy = AP_SCAN_CONN_ALL;
}
UINT8_TO_STREAM (pp, p_params->adv_filter_policy);
UINT8_TO_STREAM (pp, p_inst->inst_id);
if (p_params->tx_power > BTM_BLE_ADV_TX_POWER_MAX) {
p_params->tx_power = BTM_BLE_ADV_TX_POWER_MAX;
}
UINT8_TO_STREAM (pp, btm_ble_map_adv_tx_power(p_params->tx_power));
BTM_TRACE_EVENT("set_params:Chnl Map %d,adv_fltr policy %d,ID:%d, TX Power%d",
p_params->channel_map, p_params->adv_filter_policy, p_inst->inst_id, p_params->tx_power);
if ((rt = BTM_VendorSpecificCommand (HCI_BLE_MULTI_ADV_OCF,
BTM_BLE_MULTI_ADV_SET_PARAM_LEN,
param,
btm_ble_multi_adv_vsc_cmpl_cback))
== BTM_CMD_STARTED) {
p_inst->adv_evt = p_params->adv_type;
#if (defined BLE_PRIVACY_SPT && BLE_PRIVACY_SPT == TRUE)
if (btm_cb.ble_ctr_cb.privacy_mode != BTM_PRIVACY_NONE) {
/* start timer */
p_inst->raddr_timer_ent.param = (TIMER_PARAM_TYPE) p_inst;
btu_start_timer_oneshot(&p_inst->raddr_timer_ent, BTU_TTYPE_BLE_RANDOM_ADDR,
BTM_BLE_PRIVATE_ADDR_INT);
}
#endif
btm_ble_multi_adv_enq_op_q(BTM_BLE_MULTI_ADV_SET_PARAM, p_inst->inst_id, cb_evt);
}
return rt;
}
/*******************************************************************************
**
** Function btm_ble_multi_adv_write_rpa
**
** Description This function write the random address for the adv instance into
** controller
**
** Parameters
**
** Returns status
**
*******************************************************************************/
tBTM_STATUS btm_ble_multi_adv_write_rpa (tBTM_BLE_MULTI_ADV_INST *p_inst, BD_ADDR random_addr)
{
UINT8 param[BTM_BLE_MULTI_ADV_SET_RANDOM_ADDR_LEN], *pp = param;
tBTM_STATUS rt;
BTM_TRACE_EVENT ("%s-BD_ADDR:%02x-%02x-%02x-%02x-%02x-%02x,inst_id:%d",
__FUNCTION__, random_addr[5], random_addr[4], random_addr[3], random_addr[2],
random_addr[1], random_addr[0], p_inst->inst_id);
memset(param, 0, BTM_BLE_MULTI_ADV_SET_RANDOM_ADDR_LEN);
UINT8_TO_STREAM (pp, BTM_BLE_MULTI_ADV_SET_RANDOM_ADDR);
BDADDR_TO_STREAM(pp, random_addr);
UINT8_TO_STREAM(pp, p_inst->inst_id);
if ((rt = BTM_VendorSpecificCommand (HCI_BLE_MULTI_ADV_OCF,
BTM_BLE_MULTI_ADV_SET_RANDOM_ADDR_LEN,
param,
btm_ble_multi_adv_vsc_cmpl_cback)) == BTM_CMD_STARTED) {
/* start a periodical timer to refresh random addr */
btu_stop_timer_oneshot(&p_inst->raddr_timer_ent);
p_inst->raddr_timer_ent.param = (TIMER_PARAM_TYPE) p_inst;
btu_start_timer_oneshot(&p_inst->raddr_timer_ent, BTU_TTYPE_BLE_RANDOM_ADDR,
BTM_BLE_PRIVATE_ADDR_INT);
btm_ble_multi_adv_enq_op_q(BTM_BLE_MULTI_ADV_SET_RANDOM_ADDR, p_inst->inst_id, 0);
}
return rt;
}
/*******************************************************************************
**
** Function btm_ble_multi_adv_gen_rpa_cmpl
**
** Description RPA generation completion callback for each adv instance. Will
** continue write the new RPA into controller.
**
** Returns none.
**
*******************************************************************************/
void btm_ble_multi_adv_gen_rpa_cmpl(tBTM_RAND_ENC *p)
{
#if (SMP_INCLUDED == TRUE)
tSMP_ENC output;
UINT8 index = 0;
tBTM_BLE_MULTI_ADV_INST *p_inst = NULL;
/* Retrieve the index of adv instance from stored Q */
if (btm_multi_adv_idx_q.front == -1) {
BTM_TRACE_ERROR(" %s can't locate advertise instance", __FUNCTION__);
return;
} else {
index = btm_multi_adv_idx_q.inst_index_queue[btm_multi_adv_idx_q.front];
if (btm_multi_adv_idx_q.front == btm_multi_adv_idx_q.rear) {
btm_multi_adv_idx_q.front = -1;
btm_multi_adv_idx_q.rear = -1;
} else {
btm_multi_adv_idx_q.front = (btm_multi_adv_idx_q.front + 1) % BTM_BLE_MULTI_ADV_MAX;
}
}
p_inst = &(btm_multi_adv_cb.p_adv_inst[index]);
BTM_TRACE_EVENT ("btm_ble_multi_adv_gen_rpa_cmpl inst_id = %d", p_inst->inst_id);
if (p) {
p->param_buf[2] &= (~BLE_RESOLVE_ADDR_MASK);
p->param_buf[2] |= BLE_RESOLVE_ADDR_MSB;
p_inst->rpa[2] = p->param_buf[0];
p_inst->rpa[1] = p->param_buf[1];
p_inst->rpa[0] = p->param_buf[2];
if (!SMP_Encrypt(btm_cb.devcb.id_keys.irk, BT_OCTET16_LEN, p->param_buf, 3, &output)) {
BTM_TRACE_DEBUG("generate random address failed");
} else {
/* set hash to be LSB of rpAddress */
p_inst->rpa[5] = output.param_buf[0];
p_inst->rpa[4] = output.param_buf[1];
p_inst->rpa[3] = output.param_buf[2];
}
if (p_inst->inst_id != BTM_BLE_MULTI_ADV_DEFAULT_STD &&
p_inst->inst_id < BTM_BleMaxMultiAdvInstanceCount()) {
/* set it to controller */
btm_ble_multi_adv_write_rpa(p_inst, p_inst->rpa);
}
}
#endif
}
/*******************************************************************************
**
** Function btm_ble_multi_adv_configure_rpa
**
** Description This function set the random address for the adv instance
**
** Parameters advertise parameters used for this instance.
**
** Returns none
**
*******************************************************************************/
void btm_ble_multi_adv_configure_rpa (tBTM_BLE_MULTI_ADV_INST *p_inst)
{
if (btm_multi_adv_idx_q.front == (btm_multi_adv_idx_q.rear + 1) % BTM_BLE_MULTI_ADV_MAX) {
BTM_TRACE_ERROR("outstanding rand generation exceeded max allowed ");
return;
} else {
if (btm_multi_adv_idx_q.front == -1) {
btm_multi_adv_idx_q.front = 0;
btm_multi_adv_idx_q.rear = 0;
} else {
btm_multi_adv_idx_q.rear = (btm_multi_adv_idx_q.rear + 1) % BTM_BLE_MULTI_ADV_MAX;
}
btm_multi_adv_idx_q.inst_index_queue[btm_multi_adv_idx_q.rear] = p_inst->index;
}
btm_gen_resolvable_private_addr((void *)btm_ble_multi_adv_gen_rpa_cmpl);
}
/*******************************************************************************
**
** Function btm_ble_multi_adv_reenable
**
** Description This function re-enable adv instance upon a connection establishment.
**
** Parameters advertise parameters used for this instance.
**
** Returns none.
**
*******************************************************************************/
void btm_ble_multi_adv_reenable(UINT8 inst_id)
{
tBTM_BLE_MULTI_ADV_INST *p_inst = &btm_multi_adv_cb.p_adv_inst[inst_id - 1];
if (TRUE == p_inst->in_use) {
if (p_inst->adv_evt != BTM_BLE_CONNECT_DIR_EVT) {
btm_ble_enable_multi_adv (TRUE, p_inst->inst_id, 0);
} else
/* mark directed adv as disabled if adv has been stopped */
{
(p_inst->p_cback)(BTM_BLE_MULTI_ADV_DISABLE_EVT, p_inst->inst_id, p_inst->p_ref, 0);
p_inst->in_use = FALSE;
}
}
}
/*******************************************************************************
**
** Function btm_ble_multi_adv_enb_privacy
**
** Description This function enable/disable privacy setting in multi adv
**
** Parameters enable: enable or disable the adv instance.
**
** Returns none.
**
*******************************************************************************/
void btm_ble_multi_adv_enb_privacy(BOOLEAN enable)
{
UINT8 i;
tBTM_BLE_MULTI_ADV_INST *p_inst = &btm_multi_adv_cb.p_adv_inst[0];
for (i = 0; i < BTM_BleMaxMultiAdvInstanceCount() - 1; i ++, p_inst++) {
p_inst->in_use = FALSE;
if (enable) {
btm_ble_multi_adv_configure_rpa (p_inst);
} else {
btu_stop_timer_oneshot(&p_inst->raddr_timer_ent);
}
}
}
/*******************************************************************************
**
** Function BTM_BleEnableAdvInstance
**
** Description This function enable a Multi-ADV instance with the specified
** adv parameters
**
** Parameters p_params: pointer to the adv parameter structure, set as default
** adv parameter when the instance is enabled.
** p_cback: callback function for the adv instance.
** p_ref: reference data attach to the adv instance to be enabled.
**
** Returns status
**
*******************************************************************************/
tBTM_STATUS BTM_BleEnableAdvInstance (tBTM_BLE_ADV_PARAMS *p_params,
tBTM_BLE_MULTI_ADV_CBACK *p_cback, void *p_ref)
{
UINT8 i;
tBTM_STATUS rt = BTM_NO_RESOURCES;
tBTM_BLE_MULTI_ADV_INST *p_inst = &btm_multi_adv_cb.p_adv_inst[0];
BTM_TRACE_EVENT("BTM_BleEnableAdvInstance called");
if (0 == btm_cb.cmn_ble_vsc_cb.adv_inst_max) {
BTM_TRACE_ERROR("Controller does not support Multi ADV");
return BTM_ERR_PROCESSING;
}
if (NULL == p_inst) {
BTM_TRACE_ERROR("Invalid instance in BTM_BleEnableAdvInstance");
return BTM_ERR_PROCESSING;
}
for (i = 0; i < BTM_BleMaxMultiAdvInstanceCount() - 1; i ++, p_inst++) {
if (FALSE == p_inst->in_use) {
p_inst->in_use = TRUE;
/* configure adv parameter */
if (p_params) {
rt = btm_ble_multi_adv_set_params(p_inst, p_params, 0);
} else {
rt = BTM_CMD_STARTED;
}
/* enable adv */
BTM_TRACE_EVENT("btm_ble_enable_multi_adv being called with inst_id:%d",
p_inst->inst_id);
if (BTM_CMD_STARTED == rt) {
if ((rt = btm_ble_enable_multi_adv (TRUE, p_inst->inst_id,
BTM_BLE_MULTI_ADV_ENB_EVT)) == BTM_CMD_STARTED) {
p_inst->p_cback = p_cback;
p_inst->p_ref = p_ref;
}
}
if (BTM_CMD_STARTED != rt) {
p_inst->in_use = FALSE;
BTM_TRACE_ERROR("BTM_BleEnableAdvInstance failed");
}
break;
}
}
return rt;
}
/*******************************************************************************
**
** Function BTM_BleUpdateAdvInstParam
**
** Description This function update a Multi-ADV instance with the specified
** adv parameters.
**
** Parameters inst_id: adv instance ID
** p_params: pointer to the adv parameter structure.
**
** Returns status
**
*******************************************************************************/
tBTM_STATUS BTM_BleUpdateAdvInstParam (UINT8 inst_id, tBTM_BLE_ADV_PARAMS *p_params)
{
tBTM_STATUS rt = BTM_ILLEGAL_VALUE;
tBTM_BLE_MULTI_ADV_INST *p_inst = &btm_multi_adv_cb.p_adv_inst[inst_id - 1];
BTM_TRACE_EVENT("BTM_BleUpdateAdvInstParam called with inst_id:%d", inst_id);
if (0 == btm_cb.cmn_ble_vsc_cb.adv_inst_max) {
BTM_TRACE_ERROR("Controller does not support Multi ADV");
return BTM_ERR_PROCESSING;
}
if (inst_id < BTM_BleMaxMultiAdvInstanceCount() &&
inst_id != BTM_BLE_MULTI_ADV_DEFAULT_STD &&
p_params != NULL) {
if (FALSE == p_inst->in_use) {
BTM_TRACE_DEBUG("adv instance %d is not active", inst_id);
return BTM_WRONG_MODE;
} else {
btm_ble_enable_multi_adv(FALSE, inst_id, 0);
}
if (BTM_CMD_STARTED == btm_ble_multi_adv_set_params(p_inst, p_params, 0)) {
rt = btm_ble_enable_multi_adv(TRUE, inst_id, BTM_BLE_MULTI_ADV_PARAM_EVT);
}
}
return rt;
}
/*******************************************************************************
**
** Function BTM_BleCfgAdvInstData
**
** Description This function configure a Multi-ADV instance with the specified
** adv data or scan response data.
**
** Parameters inst_id: adv instance ID
** is_scan_rsp: is this scan response. if no, set as adv data.
** data_mask: adv data mask.
** p_data: pointer to the adv data structure.
**
** Returns status
**
*******************************************************************************/
tBTM_STATUS BTM_BleCfgAdvInstData (UINT8 inst_id, BOOLEAN is_scan_rsp,
tBTM_BLE_AD_MASK data_mask,
tBTM_BLE_ADV_DATA *p_data)
{
UINT8 param[BTM_BLE_MULTI_ADV_WRITE_DATA_LEN], *pp = param;
UINT8 sub_code = (is_scan_rsp) ?
BTM_BLE_MULTI_ADV_WRITE_SCAN_RSP_DATA : BTM_BLE_MULTI_ADV_WRITE_ADV_DATA;
UINT8 *p_len;
tBTM_STATUS rt;
UINT8 *pp_temp = (UINT8 *)(param + BTM_BLE_MULTI_ADV_WRITE_DATA_LEN - 1);
tBTM_BLE_VSC_CB cmn_ble_vsc_cb;
BTM_BleGetVendorCapabilities(&cmn_ble_vsc_cb);
if (0 == cmn_ble_vsc_cb.adv_inst_max) {
BTM_TRACE_ERROR("Controller does not support Multi ADV");
return BTM_ERR_PROCESSING;
}
btm_ble_update_dmt_flag_bits(&p_data->flag, btm_cb.btm_inq_vars.connectable_mode,
btm_cb.btm_inq_vars.discoverable_mode);
BTM_TRACE_EVENT("BTM_BleCfgAdvInstData called with inst_id:%d", inst_id);
if (inst_id > BTM_BLE_MULTI_ADV_MAX || inst_id == BTM_BLE_MULTI_ADV_DEFAULT_STD) {
return BTM_ILLEGAL_VALUE;
}
memset(param, 0, BTM_BLE_MULTI_ADV_WRITE_DATA_LEN);
UINT8_TO_STREAM(pp, sub_code);
p_len = pp ++;
btm_ble_build_adv_data(&data_mask, &pp, p_data);
*p_len = (UINT8)(pp - param - 2);
UINT8_TO_STREAM(pp_temp, inst_id);
if ((rt = BTM_VendorSpecificCommand (HCI_BLE_MULTI_ADV_OCF,
(UINT8)BTM_BLE_MULTI_ADV_WRITE_DATA_LEN,
param,
btm_ble_multi_adv_vsc_cmpl_cback))
== BTM_CMD_STARTED) {
btm_ble_multi_adv_enq_op_q(sub_code, inst_id, BTM_BLE_MULTI_ADV_DATA_EVT);
}
return rt;
}
/*******************************************************************************
**
** Function BTM_BleDisableAdvInstance
**
** Description This function disables a Multi-ADV instance.
**
** Parameters inst_id: adv instance ID
**
** Returns status
**
*******************************************************************************/
tBTM_STATUS BTM_BleDisableAdvInstance (UINT8 inst_id)
{
tBTM_STATUS rt = BTM_ILLEGAL_VALUE;
tBTM_BLE_VSC_CB cmn_ble_vsc_cb;
BTM_TRACE_EVENT("BTM_BleDisableAdvInstance with inst_id:%d", inst_id);
BTM_BleGetVendorCapabilities(&cmn_ble_vsc_cb);
if (0 == cmn_ble_vsc_cb.adv_inst_max) {
BTM_TRACE_ERROR("Controller does not support Multi ADV");
return BTM_ERR_PROCESSING;
}
if (inst_id < BTM_BleMaxMultiAdvInstanceCount() &&
inst_id != BTM_BLE_MULTI_ADV_DEFAULT_STD) {
if ((rt = btm_ble_enable_multi_adv(FALSE, inst_id, BTM_BLE_MULTI_ADV_DISABLE_EVT))
== BTM_CMD_STARTED) {
btm_ble_multi_adv_configure_rpa(&btm_multi_adv_cb.p_adv_inst[inst_id - 1]);
btu_stop_timer_oneshot(&btm_multi_adv_cb.p_adv_inst[inst_id - 1].raddr_timer_ent);
btm_multi_adv_cb.p_adv_inst[inst_id - 1].in_use = FALSE;
}
}
return rt;
}
/*******************************************************************************
**
** Function btm_ble_multi_adv_vse_cback
**
** Description VSE callback for multi adv events.
**
** Returns
**
*******************************************************************************/
void btm_ble_multi_adv_vse_cback(UINT8 len, UINT8 *p)
{
UINT8 sub_event;
UINT8 adv_inst;
UINT16 conn_handle;
tACL_CONN *p_acl_cb = NULL;
/* Check if this is a BLE RSSI vendor specific event */
STREAM_TO_UINT8(sub_event, p);
len--;
BTM_TRACE_EVENT("btm_ble_multi_adv_vse_cback called with event:%d", sub_event);
if ((sub_event == HCI_VSE_SUBCODE_BLE_MULTI_ADV_ST_CHG) && (len >= 4)) {
STREAM_TO_UINT8(adv_inst, p);
++p;
STREAM_TO_UINT16(conn_handle, p);
if ((p_acl_cb = btm_handle_to_acl(conn_handle)) != NULL) {
#if (defined BLE_PRIVACY_SPT && BLE_PRIVACY_SPT == TRUE)
if (btm_cb.ble_ctr_cb.privacy_mode != BTM_PRIVACY_NONE &&
adv_inst <= BTM_BLE_MULTI_ADV_MAX && adv_inst != BTM_BLE_MULTI_ADV_DEFAULT_STD) {
memcpy(p_acl_cb->conn_addr, btm_multi_adv_cb.p_adv_inst[adv_inst - 1].rpa,
BD_ADDR_LEN);
}
#endif
}
if (adv_inst < BTM_BleMaxMultiAdvInstanceCount() &&
adv_inst != BTM_BLE_MULTI_ADV_DEFAULT_STD) {
BTM_TRACE_EVENT("btm_ble_multi_adv_reenable called");
btm_ble_multi_adv_reenable(adv_inst);
}
/* re-enable connectibility */
else if (adv_inst == BTM_BLE_MULTI_ADV_DEFAULT_STD) {
if (btm_cb.ble_ctr_cb.inq_var.connectable_mode == BTM_BLE_CONNECTABLE) {
btm_ble_set_connectability ( btm_cb.ble_ctr_cb.inq_var.connectable_mode );
}
}
}
}
/*******************************************************************************
**
** Function btm_ble_multi_adv_init
**
** Description This function initialize the multi adv control block.
**
** Parameters None
**
** Returns void
**
*******************************************************************************/
void btm_ble_multi_adv_init(void)
{
#if BTM_DYNAMIC_MEMORY == TRUE
btm_multi_adv_cb_ptr = (tBTM_BLE_MULTI_ADV_CB *)osi_malloc(sizeof(tBTM_BLE_MULTI_ADV_CB));
btm_multi_adv_idx_q_ptr = (tBTM_BLE_MULTI_ADV_INST_IDX_Q *)osi_malloc(sizeof(tBTM_BLE_MULTI_ADV_INST_IDX_Q));
if (btm_multi_adv_cb_ptr == NULL || btm_multi_adv_idx_q_ptr == NULL) {
BTM_TRACE_ERROR("%s malloc failed", __func__);
return;
}
#endif
UINT8 i = 0;
memset(&btm_multi_adv_cb, 0, sizeof(tBTM_BLE_MULTI_ADV_CB));
memset (&btm_multi_adv_idx_q, 0, sizeof (tBTM_BLE_MULTI_ADV_INST_IDX_Q));
btm_multi_adv_idx_q.front = -1;
btm_multi_adv_idx_q.rear = -1;
if (btm_cb.cmn_ble_vsc_cb.adv_inst_max > 0) {
btm_multi_adv_cb.p_adv_inst = osi_malloc( sizeof(tBTM_BLE_MULTI_ADV_INST) *
(btm_cb.cmn_ble_vsc_cb.adv_inst_max));
memset(btm_multi_adv_cb.p_adv_inst, 0, sizeof(tBTM_BLE_MULTI_ADV_INST) *
(btm_cb.cmn_ble_vsc_cb.adv_inst_max));
btm_multi_adv_cb.op_q.p_sub_code = osi_malloc( sizeof(UINT8) *
(btm_cb.cmn_ble_vsc_cb.adv_inst_max));
memset(btm_multi_adv_cb.op_q.p_sub_code, 0,
sizeof(UINT8) * (btm_cb.cmn_ble_vsc_cb.adv_inst_max));
btm_multi_adv_cb.op_q.p_inst_id = osi_malloc( sizeof(UINT8) *
(btm_cb.cmn_ble_vsc_cb.adv_inst_max));
memset(btm_multi_adv_cb.op_q.p_inst_id, 0,
sizeof(UINT8) * (btm_cb.cmn_ble_vsc_cb.adv_inst_max));
}
/* Initialize adv instance indices and IDs. */
for (i = 0; i < btm_cb.cmn_ble_vsc_cb.adv_inst_max; i++) {
btm_multi_adv_cb.p_adv_inst[i].index = i;
btm_multi_adv_cb.p_adv_inst[i].inst_id = i + 1;
}
BTM_RegisterForVSEvents(btm_ble_multi_adv_vse_cback, TRUE);
}
/*******************************************************************************
**
** Function btm_ble_multi_adv_cleanup
**
** Description This function cleans up multi adv control block.
**
** Parameters
** Returns void
**
*******************************************************************************/
void btm_ble_multi_adv_cleanup(void)
{
if (btm_multi_adv_cb.p_adv_inst) {
osi_free(btm_multi_adv_cb.p_adv_inst);
btm_multi_adv_cb.p_adv_inst = NULL;
}
if (btm_multi_adv_cb.op_q.p_sub_code) {
osi_free(btm_multi_adv_cb.op_q.p_sub_code);
btm_multi_adv_cb.op_q.p_sub_code = NULL;
}
if (btm_multi_adv_cb.op_q.p_inst_id) {
osi_free(btm_multi_adv_cb.op_q.p_inst_id);
btm_multi_adv_cb.op_q.p_inst_id = NULL;
}
#if BTM_DYNAMIC_MEMORY == TRUE
if(btm_multi_adv_cb_ptr) {
osi_free(btm_multi_adv_cb_ptr);
btm_multi_adv_cb_ptr = NULL;
}
if(btm_multi_adv_idx_q_ptr) {
osi_free(btm_multi_adv_idx_q_ptr);
btm_multi_adv_idx_q_ptr = NULL;
}
#endif
}
/*******************************************************************************
**
** Function btm_ble_multi_adv_get_ref
**
** Description This function obtains the reference pointer for the instance ID provided
**
** Parameters inst_id - Instance ID
**
** Returns void*
**
*******************************************************************************/
void *btm_ble_multi_adv_get_ref(UINT8 inst_id)
{
tBTM_BLE_MULTI_ADV_INST *p_inst = NULL;
if (inst_id < BTM_BleMaxMultiAdvInstanceCount()) {
p_inst = &btm_multi_adv_cb.p_adv_inst[inst_id - 1];
if (NULL != p_inst) {
return p_inst->p_ref;
}
}
return NULL;
}
#endif
File diff suppressed because it is too large Load Diff
+741
View File
@@ -0,0 +1,741 @@
/******************************************************************************
*
* Copyright (C) 1999-2012 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.
*
******************************************************************************/
/******************************************************************************
*
* This file contains functions for the Bluetooth Device Manager
*
******************************************************************************/
#include <stdlib.h>
#include <string.h>
//#include <stdio.h>
#include <stddef.h>
#include "stack/bt_types.h"
#include "device/controller.h"
#include "stack/hcimsgs.h"
#include "stack/btu.h"
#include "stack/btm_api.h"
#include "btm_int.h"
#include "stack/hcidefs.h"
#include "stack/l2c_api.h"
static tBTM_SEC_DEV_REC *btm_find_oldest_dev (void);
/*******************************************************************************
**
** Function BTM_SecAddDevice
**
** Description Add/modify device. This function will be normally called
** during host startup to restore all required information
** stored in the NVRAM.
**
** Parameters: bd_addr - BD address of the peer
** dev_class - Device Class
** bd_name - Name of the peer device. NULL if unknown.
** features - Remote device's features (up to 3 pages). NULL if not known
** trusted_mask - Bitwise OR of services that do not
** require authorization. (array of UINT32)
** link_key - Connection link key. NULL if unknown.
**
** Returns TRUE if added OK, else FALSE
**
*******************************************************************************/
BOOLEAN BTM_SecAddDevice (BD_ADDR bd_addr, DEV_CLASS dev_class, BD_NAME bd_name,
UINT8 *features, UINT32 trusted_mask[],
LINK_KEY link_key, UINT8 key_type, tBTM_IO_CAP io_cap,
UINT8 pin_length, UINT8 sc_support)
{
#if (SMP_INCLUDED == TRUE)
tBTM_SEC_DEV_REC *p_dev_rec;
int i, j;
BOOLEAN found = FALSE;
BTM_TRACE_API("%s, link key type:%x\n", __FUNCTION__, key_type);
p_dev_rec = btm_find_dev (bd_addr);
if (!p_dev_rec) {
/* There is no device record, allocate one.
* If we can not find an empty spot for this one, let it fail. */
if (list_length(btm_cb.p_sec_dev_rec_list) < BTM_SEC_MAX_DEVICE_RECORDS) {
p_dev_rec = (tBTM_SEC_DEV_REC *)osi_malloc(sizeof(tBTM_SEC_DEV_REC));
if(p_dev_rec) {
list_append(btm_cb.p_sec_dev_rec_list, p_dev_rec);
/* Mark this record as in use and initialize */
memset (p_dev_rec, 0, sizeof (tBTM_SEC_DEV_REC));
p_dev_rec->sec_flags = BTM_SEC_IN_USE;
memcpy (p_dev_rec->bd_addr, bd_addr, BD_ADDR_LEN);
p_dev_rec->hci_handle = BTM_GetHCIConnHandle (bd_addr, BT_TRANSPORT_BR_EDR);
p_dev_rec->ble_hci_handle = BTM_GetHCIConnHandle (bd_addr, BT_TRANSPORT_LE);
p_dev_rec->enc_mode = BTM_ENC_MODE_UNKNOWN;
#if BLE_INCLUDED == TRUE
/* use default value for background connection params */
/* update conn params, use default value for background connection params */
memset(&p_dev_rec->conn_params, 0xff, sizeof(tBTM_LE_CONN_PRAMS));
#endif
}
}
if (!p_dev_rec) {
return (FALSE);
}
}
p_dev_rec->bond_type = BOND_TYPE_UNKNOWN; /* Default value */
p_dev_rec->timestamp = btm_cb.dev_rec_count++;
p_dev_rec->remote_secure_connection_previous_state = sc_support;
if (dev_class) {
memcpy (p_dev_rec->dev_class, dev_class, DEV_CLASS_LEN);
}
memset(p_dev_rec->sec_bd_name, 0, sizeof(tBTM_BD_NAME));
if (bd_name && bd_name[0]) {
p_dev_rec->sec_flags |= BTM_SEC_NAME_KNOWN;
BCM_STRNCPY_S ((char *)p_dev_rec->sec_bd_name, (char *)bd_name, BTM_MAX_REM_BD_NAME_LEN);
}
p_dev_rec->num_read_pages = 0;
if (features) {
memcpy (p_dev_rec->features, features, sizeof (p_dev_rec->features));
for (i = HCI_EXT_FEATURES_PAGE_MAX; i >= 0; i--) {
for (j = 0; j < HCI_FEATURE_BYTES_PER_PAGE; j++) {
if (p_dev_rec->features[i][j] != 0) {
found = TRUE;
break;
}
}
if (found) {
p_dev_rec->num_read_pages = i + 1;
break;
}
}
} else {
memset (p_dev_rec->features, 0, sizeof (p_dev_rec->features));
}
BTM_SEC_COPY_TRUSTED_DEVICE(trusted_mask, p_dev_rec->trusted_mask);
if (link_key) {
BTM_TRACE_EVENT ("BTM_SecAddDevice() BDA: %02x:%02x:%02x:%02x:%02x:%02x\n",
bd_addr[0], bd_addr[1], bd_addr[2],
bd_addr[3], bd_addr[4], bd_addr[5]);
p_dev_rec->sec_flags |= BTM_SEC_LINK_KEY_KNOWN;
memcpy (p_dev_rec->link_key, link_key, LINK_KEY_LEN);
p_dev_rec->link_key_type = key_type;
p_dev_rec->pin_code_length = pin_length;
if (pin_length >= 16 ||
key_type == BTM_LKEY_TYPE_AUTH_COMB ||
key_type == BTM_LKEY_TYPE_AUTH_COMB_P_256) {
// Set the fiag if the link key was made by using either a 16 digit
// pin or MITM.
p_dev_rec->sec_flags |= BTM_SEC_16_DIGIT_PIN_AUTHED;
}
}
#if defined(BTIF_MIXED_MODE_INCLUDED) && (BTIF_MIXED_MODE_INCLUDED == TRUE)
if (key_type < BTM_MAX_PRE_SM4_LKEY_TYPE) {
p_dev_rec->sm4 = BTM_SM4_KNOWN;
} else {
p_dev_rec->sm4 = BTM_SM4_TRUE;
}
#endif
p_dev_rec->rmt_io_caps = io_cap;
p_dev_rec->device_type |= BT_DEVICE_TYPE_BREDR;
#endif ///SMP_INCLUDED == TRUE
return (TRUE);
}
/*******************************************************************************
**
** Function BTM_SecDeleteDevice
**
** Description Free resources associated with the device.
**
** Parameters: bd_addr - BD address of the peer
** transport - BT_TRANSPORT_BR_EDR or BT_TRANSPORT_LE
**
** Returns TRUE if removed OK, FALSE if not found or ACL link is active
**
*******************************************************************************/
BOOLEAN BTM_SecDeleteDevice (BD_ADDR bd_addr, tBT_TRANSPORT transport)
{
tBTM_SEC_DEV_REC *p_dev_rec;
if (BTM_IsAclConnectionUp(bd_addr, transport)) {
BTM_TRACE_WARNING("%s FAILED: Cannot Delete when connection is active\n", __func__);
return FALSE;
}
if ((p_dev_rec = btm_find_dev(bd_addr)) != NULL) {
/* Tell controller to get rid of the link key, if it has one stored */
BTM_DeleteStoredLinkKey (p_dev_rec->bd_addr, NULL);
btm_sec_free_dev(p_dev_rec, transport);
}
return TRUE;
}
/*******************************************************************************
**
** Function BTM_SecClearSecurityFlags
**
** Description Reset the security flags (mark as not-paired) for a given
** remove device.
**
*******************************************************************************/
extern void BTM_SecClearSecurityFlags (BD_ADDR bd_addr)
{
tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev(bd_addr);
if (p_dev_rec == NULL) {
return;
}
p_dev_rec->sec_flags = 0;
p_dev_rec->sec_state = BTM_SEC_STATE_IDLE;
p_dev_rec->sm4 = BTM_SM4_UNKNOWN;
}
/*******************************************************************************
**
** Function BTM_SecReadDevName
**
** Description Looks for the device name in the security database for the
** specified BD address.
**
** Returns Pointer to the name or NULL
**
*******************************************************************************/
char *BTM_SecReadDevName (BD_ADDR bd_addr)
{
char *p_name = NULL;
tBTM_SEC_DEV_REC *p_srec;
if ((p_srec = btm_find_dev(bd_addr)) != NULL) {
p_name = (char *)p_srec->sec_bd_name;
}
return (p_name);
}
/*******************************************************************************
**
** Function btm_find_sec_dev_in_list
**
** Description Look for the record in the device database for the record
** with specified address
**
** Returns Pointer to the record or NULL
**
*******************************************************************************/
BOOLEAN btm_find_sec_dev_in_list (void *p_node_data, void *context)
{
tBTM_SEC_DEV_REC *p_sec_dev = (tBTM_SEC_DEV_REC *)p_node_data;
BOOLEAN ret = TRUE;
BOOLEAN dev_free = !(p_sec_dev->sec_flags & BTM_SEC_IN_USE);
tSecDevContext *p_context = (tSecDevContext *)context;
if (dev_free == p_context->free_check) {
switch (p_context->type) {
case SEC_DEV_BDA:
if (!memcmp(p_context->context.p_bd_addr, p_sec_dev->bd_addr, BD_ADDR_LEN)) {
ret = FALSE;
}
break;
case SEC_DEV_HDL:
if (p_context->context.handle == p_sec_dev->hci_handle
#if BLE_INCLUDED == TRUE
|| (p_context->context.handle == p_sec_dev->ble_hci_handle)
#endif
) {
ret = FALSE;
}
break;
#if BLE_PRIVACY_SPT == TRUE
case SEC_DEV_ID_ADDR:
if (!memcmp(p_context->context.p_bd_addr, p_sec_dev->ble.static_addr, BD_ADDR_LEN)) {
ret = FALSE;
}
break;
#endif //BLE_PRIVACY_SPT == TRUE
case SEC_DEV_BTDM_BDA:
if (!memcmp(p_context->context.p_bd_addr, p_sec_dev->bd_addr, BD_ADDR_LEN)) {
ret = FALSE;
}
#if BLE_INCLUDED == TRUE
// If a LE random address is looking for device record
if (!memcmp(p_sec_dev->ble.pseudo_addr, p_context->context.p_bd_addr, BD_ADDR_LEN)) {
ret = FALSE;
}
if (btm_ble_addr_resolvable(p_context->context.p_bd_addr, p_sec_dev)) {
ret = FALSE;
}
#endif
break;
default:
break;
}
}
return ret;
}
/*******************************************************************************
**
** Function btm_sec_alloc_dev
**
** Description Look for the record in the device database for the record
** with specified address
**
** Returns Pointer to the record or NULL
**
*******************************************************************************/
tBTM_SEC_DEV_REC *btm_sec_alloc_dev (BD_ADDR bd_addr)
{
tBTM_SEC_DEV_REC *p_dev_rec = NULL;
tBTM_SEC_DEV_REC *p_dev_new_rec = NULL;
tBTM_SEC_DEV_REC *p_dev_old_rec = NULL;
tBTM_INQ_INFO *p_inq_info;
list_node_t *p_node = NULL;
BOOLEAN new_entry_found = FALSE;
BOOLEAN old_entry_found = FALSE;
BOOLEAN malloc_new_entry = FALSE;
BTM_TRACE_EVENT ("btm_sec_alloc_dev\n");
for (p_node = list_begin(btm_cb.p_sec_dev_rec_list); p_node; p_node = list_next(p_node)) {
p_dev_old_rec = list_node(p_node);
/* look for old entry which match the bd_addr and the BTM_SEC_IN_USE is cleared */
if (!(p_dev_old_rec->sec_flags & BTM_SEC_IN_USE) &&
(!memcmp (p_dev_old_rec->bd_addr, bd_addr, BD_ADDR_LEN))) {
old_entry_found = TRUE;
BTM_TRACE_EVENT ("btm_sec_alloc_dev old device found\n");
break;
}
}
for (p_node = list_begin(btm_cb.p_sec_dev_rec_list); p_node; p_node = list_next(p_node)) {
p_dev_new_rec = list_node(p_node);
/* find the first entry whose BTM_SEC_IN_USE is cleared */
if (!(p_dev_new_rec->sec_flags & BTM_SEC_IN_USE)) {
new_entry_found = TRUE;
break;
}
}
if (!new_entry_found) {
/* We can not find new device. We need malloc a new one if p_sec_dev_rec_list is not full */
if (list_length(btm_cb.p_sec_dev_rec_list) < BTM_SEC_MAX_DEVICE_RECORDS){
p_dev_new_rec = (tBTM_SEC_DEV_REC *)osi_malloc(sizeof(tBTM_SEC_DEV_REC));
if (p_dev_new_rec) {
new_entry_found = TRUE;
malloc_new_entry = TRUE;
} else {
return NULL;
}
}
}
if (!new_entry_found) {
p_dev_rec = btm_find_oldest_dev();
} else {
/* if the old device entry not present go with new entry */
if (old_entry_found) {
p_dev_rec = p_dev_old_rec;
if (malloc_new_entry) {
osi_free(p_dev_new_rec);
}
} else {
if (malloc_new_entry) {
list_append(btm_cb.p_sec_dev_rec_list, p_dev_new_rec);
}
p_dev_rec = p_dev_new_rec;
}
}
memset (p_dev_rec, 0, sizeof (tBTM_SEC_DEV_REC));
p_dev_rec->bond_type = BOND_TYPE_UNKNOWN; /* Default value */
p_dev_rec->sec_flags = BTM_SEC_IN_USE;
/* Check with the BT manager if details about remote device are known */
/* outgoing connection */
if ((p_inq_info = BTM_InqDbRead(bd_addr)) != NULL) {
memcpy (p_dev_rec->dev_class, p_inq_info->results.dev_class, DEV_CLASS_LEN);
#if BLE_INCLUDED == TRUE
p_dev_rec->device_type = p_inq_info->results.device_type;
p_dev_rec->ble.ble_addr_type = p_inq_info->results.ble_addr_type;
/* update conn params, use default value for background connection params */
memset(&p_dev_rec->conn_params, 0xff, sizeof(tBTM_LE_CONN_PRAMS));
#endif
} else {
#if BLE_INCLUDED == TRUE
/* update conn params, use default value for background connection params */
memset(&p_dev_rec->conn_params, 0xff, sizeof(tBTM_LE_CONN_PRAMS));
#endif
if (!memcmp (bd_addr, btm_cb.connecting_bda, BD_ADDR_LEN)) {
memcpy (p_dev_rec->dev_class, btm_cb.connecting_dc, DEV_CLASS_LEN);
}
}
memcpy (p_dev_rec->bd_addr, bd_addr, BD_ADDR_LEN);
#if BLE_INCLUDED == TRUE
p_dev_rec->ble_hci_handle = BTM_GetHCIConnHandle (bd_addr, BT_TRANSPORT_LE);
#endif
p_dev_rec->hci_handle = BTM_GetHCIConnHandle (bd_addr, BT_TRANSPORT_BR_EDR);
p_dev_rec->timestamp = btm_cb.dev_rec_count++;
return (p_dev_rec);
}
/*******************************************************************************
**
** Function btm_sec_free_dev
**
** Description Mark device record as not used
**
*******************************************************************************/
void btm_sec_free_dev (tBTM_SEC_DEV_REC *p_dev_rec, tBT_TRANSPORT transport)
{
if (transport == BT_TRANSPORT_BR_EDR) {
memset(p_dev_rec->link_key, 0, LINK_KEY_LEN);
p_dev_rec->sec_flags &= ~(BTM_SEC_AUTHORIZED | BTM_SEC_AUTHENTICATED
| BTM_SEC_ENCRYPTED | BTM_SEC_NAME_KNOWN
| BTM_SEC_LINK_KEY_KNOWN | BTM_SEC_LINK_KEY_AUTHED
| BTM_SEC_ROLE_SWITCHED | BTM_SEC_16_DIGIT_PIN_AUTHED);
} else if (transport == BT_TRANSPORT_LE) {
p_dev_rec->bond_type = BOND_TYPE_UNKNOWN;
p_dev_rec->sec_flags &= ~(BTM_SEC_LE_AUTHENTICATED | BTM_SEC_LE_ENCRYPTED
| BTM_SEC_LE_NAME_KNOWN | BTM_SEC_LE_LINK_KEY_KNOWN
| BTM_SEC_LE_LINK_KEY_AUTHED | BTM_SEC_ROLE_SWITCHED);
#if BLE_INCLUDED == TRUE
/* Clear out any saved BLE keys */
btm_sec_clear_ble_keys (p_dev_rec);
#endif
} else {
p_dev_rec->bond_type = BOND_TYPE_UNKNOWN;
memset(p_dev_rec->link_key, 0, LINK_KEY_LEN);
p_dev_rec->sec_flags = 0;
#if BLE_INCLUDED == TRUE
/* Clear out any saved BLE keys */
btm_sec_clear_ble_keys (p_dev_rec);
#endif
}
/* No BLE keys and BT keys, clear the sec_flags */
if(p_dev_rec->sec_flags == BTM_SEC_IN_USE) {
p_dev_rec->sec_flags = 0;
}
list_remove(btm_cb.p_sec_dev_rec_list, p_dev_rec);
}
/*******************************************************************************
**
** Function btm_dev_support_switch
**
** Description This function is called by the L2CAP to check if remote
** device supports role switch
**
** Parameters: bd_addr - Address of the peer device
**
** Returns TRUE if device is known and role switch is supported
**
*******************************************************************************/
BOOLEAN btm_dev_support_switch (BD_ADDR bd_addr)
{
tBTM_SEC_DEV_REC *p_dev_rec;
UINT8 xx;
BOOLEAN feature_empty = TRUE;
#if BTM_SCO_INCLUDED == TRUE
/* Role switch is not allowed if a SCO is up */
if (btm_is_sco_active_by_bdaddr(bd_addr)) {
return (FALSE);
}
#endif
p_dev_rec = btm_find_dev (bd_addr);
if (p_dev_rec && controller_get_interface()->supports_master_slave_role_switch()) {
if (HCI_SWITCH_SUPPORTED(p_dev_rec->features[HCI_EXT_FEATURES_PAGE_0])) {
BTM_TRACE_DEBUG("btm_dev_support_switch return TRUE (feature found)\n");
return (TRUE);
}
/* If the feature field is all zero, we never received them */
for (xx = 0 ; xx < BD_FEATURES_LEN ; xx++) {
if (p_dev_rec->features[HCI_EXT_FEATURES_PAGE_0][xx] != 0x00) {
feature_empty = FALSE; /* at least one is != 0 */
break;
}
}
/* If we don't know peer's capabilities, assume it supports Role-switch */
if (feature_empty) {
BTM_TRACE_DEBUG("btm_dev_support_switch return TRUE (feature empty)\n");
return (TRUE);
}
}
BTM_TRACE_DEBUG("btm_dev_support_switch return FALSE\n");
return (FALSE);
}
/*******************************************************************************
**
** Function btm_find_dev_by_handle
**
** Description Look for the record in the device database for the record
** with specified handle
**
** Returns Pointer to the record or NULL
**
*******************************************************************************/
tBTM_SEC_DEV_REC *btm_find_dev_by_handle (UINT16 handle)
{
tBTM_SEC_DEV_REC *p_dev_rec = NULL;
list_node_t *p_node = NULL;
tSecDevContext context;
context.type = SEC_DEV_HDL;
context.context.handle = handle;
context.free_check = FALSE;
p_node = list_foreach(btm_cb.p_sec_dev_rec_list, btm_find_sec_dev_in_list, &context);
if (p_node) {
p_dev_rec = list_node(p_node);
}
return (p_dev_rec);
}
/*******************************************************************************
**
** Function btm_find_dev
**
** Description Look for the record in the device database for the record
** with specified BD address
**
** Returns Pointer to the record or NULL
**
*******************************************************************************/
tBTM_SEC_DEV_REC *btm_find_dev(BD_ADDR bd_addr)
{
if(bd_addr) {
list_node_t *p_node = NULL;
tSecDevContext context;
context.type = SEC_DEV_BTDM_BDA;
context.context.p_bd_addr = bd_addr;
context.free_check = FALSE;
p_node = list_foreach(btm_cb.p_sec_dev_rec_list, btm_find_sec_dev_in_list, &context);
if (p_node) {
return(list_node(p_node));
}
}
return (NULL);
}
/*******************************************************************************
**
** Function btm_consolidate_dev
**
** Description combine security records if identified as same peer
**
** Returns none
**
*******************************************************************************/
void btm_consolidate_dev(tBTM_SEC_DEV_REC *p_target_rec)
{
#if BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE
tBTM_SEC_DEV_REC *p_dev_rec = NULL;
tBTM_SEC_DEV_REC temp_rec = *p_target_rec;
list_node_t *p_node = NULL;
BTM_TRACE_DEBUG("%s\n", __func__);
for (p_node = list_begin(btm_cb.p_sec_dev_rec_list); p_node; p_node = list_next(p_node)) {
p_dev_rec = list_node(p_node);
if (p_target_rec != p_dev_rec && p_dev_rec->sec_flags & BTM_SEC_IN_USE) {
if (!memcmp (p_dev_rec->bd_addr, p_target_rec->bd_addr, BD_ADDR_LEN)) {
memcpy(p_target_rec, p_dev_rec, sizeof(tBTM_SEC_DEV_REC));
p_target_rec->ble = temp_rec.ble;
p_target_rec->ble_hci_handle = temp_rec.ble_hci_handle;
p_target_rec->enc_key_size = temp_rec.enc_key_size;
p_target_rec->conn_params = temp_rec.conn_params;
p_target_rec->device_type |= temp_rec.device_type;
p_target_rec->sec_flags |= temp_rec.sec_flags;
p_target_rec->new_encryption_key_is_p256 = temp_rec.new_encryption_key_is_p256;
p_target_rec->no_smp_on_br = temp_rec.no_smp_on_br;
p_target_rec->bond_type = temp_rec.bond_type;
/* Remove the unused device from the list */
list_remove(btm_cb.p_sec_dev_rec_list, p_dev_rec);
break;
}
/* an RPA device entry is a duplicate of the target record */
if (btm_ble_addr_resolvable(p_dev_rec->bd_addr, p_target_rec)) {
if (memcmp(p_target_rec->ble.pseudo_addr, p_dev_rec->bd_addr, BD_ADDR_LEN) == 0) {
p_target_rec->ble.ble_addr_type = p_dev_rec->ble.ble_addr_type;
p_target_rec->device_type |= p_dev_rec->device_type;
/* Remove the unused device from the list */
list_remove(btm_cb.p_sec_dev_rec_list, p_dev_rec);
}
break;
}
}
}
#endif
}
/*******************************************************************************
**
** Function btm_find_or_alloc_dev
**
** Description Look for the record in the device database for the record
** with specified BD address
**
** Returns Pointer to the record or NULL
**
*******************************************************************************/
tBTM_SEC_DEV_REC *btm_find_or_alloc_dev (BD_ADDR bd_addr)
{
tBTM_SEC_DEV_REC *p_dev_rec;
BTM_TRACE_EVENT ("btm_find_or_alloc_dev\n");
if ((p_dev_rec = btm_find_dev (bd_addr)) == NULL) {
/* Allocate a new device record or reuse the oldest one */
p_dev_rec = btm_sec_alloc_dev (bd_addr);
}
return (p_dev_rec);
}
/*******************************************************************************
**
** Function btm_find_oldest_dev
**
** Description Locates the oldest device in use. It first looks for
** the oldest non-paired device. If all devices are paired it
** deletes the oldest paired device.
**
** Returns Pointer to the record or NULL
**
*******************************************************************************/
tBTM_SEC_DEV_REC *btm_find_oldest_dev (void)
{
tBTM_SEC_DEV_REC *p_dev_rec = NULL;
tBTM_SEC_DEV_REC *p_oldest = NULL;
list_node_t *p_node = NULL;
UINT32 ot = 0xFFFFFFFF;
/* First look for the non-paired devices for the oldest entry */
for (p_node = list_begin(btm_cb.p_sec_dev_rec_list); p_node; p_node = list_next(p_node)) {
p_dev_rec = list_node(p_node);
if (((p_dev_rec->sec_flags & BTM_SEC_IN_USE) == 0)
|| ((p_dev_rec->sec_flags & (BTM_SEC_LINK_KEY_KNOWN | BTM_SEC_LE_LINK_KEY_KNOWN)) != 0)) {
continue; /* Device is paired so skip it */
}
if (p_dev_rec->timestamp < ot) {
p_oldest = p_dev_rec;
ot = p_dev_rec->timestamp;
}
}
if (ot != 0xFFFFFFFF) {
return (p_oldest);
}
/* All devices are paired; find the oldest */
for (p_node = list_begin(btm_cb.p_sec_dev_rec_list); p_node; p_node = list_next(p_node)) {
if ((p_dev_rec->sec_flags & BTM_SEC_IN_USE) == 0) {
continue;
}
if (p_dev_rec->timestamp < ot) {
p_oldest = p_dev_rec;
ot = p_dev_rec->timestamp;
}
}
return (p_oldest);
}
/*******************************************************************************
**
** Function btm_get_bond_type_dev
**
** Description Get the bond type for a device in the device database
** with specified BD address
**
** Returns The device bond type if known, otherwise BOND_TYPE_UNKNOWN
**
*******************************************************************************/
tBTM_BOND_TYPE btm_get_bond_type_dev(BD_ADDR bd_addr)
{
tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev(bd_addr);
if (p_dev_rec == NULL) {
return BOND_TYPE_UNKNOWN;
}
return p_dev_rec->bond_type;
}
/*******************************************************************************
**
** Function btm_set_bond_type_dev
**
** Description Set the bond type for a device in the device database
** with specified BD address
**
** Returns TRUE on success, otherwise FALSE
**
*******************************************************************************/
BOOLEAN btm_set_bond_type_dev(BD_ADDR bd_addr, tBTM_BOND_TYPE bond_type)
{
tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev(bd_addr);
if (p_dev_rec == NULL) {
return FALSE;
}
p_dev_rec->bond_type = bond_type;
return TRUE;
}
/*******************************************************************************
**
** Function btm_sec_dev_init
**
** Description Create new linked list for dynamic allocation on sec_dev_rec
**
*******************************************************************************/
void btm_sec_dev_init(void)
{
btm_cb.p_sec_dev_rec_list = list_new(osi_free_func);
}
/*******************************************************************************
**
** Function btm_sec_dev_free
**
** Description Delete sec_dev_rec list when btm_cb is being released
**
*******************************************************************************/
void btm_sec_dev_free(void)
{
list_free(btm_cb.p_sec_dev_rec_list);
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+152
View File
@@ -0,0 +1,152 @@
/******************************************************************************
*
* Copyright (C) 2002-2012 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.
*
******************************************************************************/
/******************************************************************************
*
* This file contains the definition of the btm control block when
* BTM_DYNAMIC_MEMORY is used.
*
******************************************************************************/
#include "stack/bt_types.h"
#include "common/bt_target.h"
#include <string.h>
#include "btm_int.h"
#include "osi/allocator.h"
/* Global BTM control block structure
*/
#if BTM_DYNAMIC_MEMORY == FALSE
tBTM_CB btm_cb;
#else
tBTM_CB *btm_cb_ptr;
#endif
#if (BLE_50_FEATURE_SUPPORT == TRUE)
extern void btm_ble_extendadvcb_init(void);
extern void btm_ble_advrecod_init(void);
#endif
/*******************************************************************************
**
** Function btm_init
**
** Description This function is called at BTM startup to allocate the
** control block (if using dynamic memory), and initializes the
** tracing level. It then initializes the various components of
** btm.
**
** Returns void
**
*******************************************************************************/
void btm_init (void)
{
#if BTM_DYNAMIC_MEMORY
btm_cb_ptr = (tBTM_CB *)osi_malloc(sizeof(tBTM_CB));
#endif /* #if BTM_DYNAMIC_MEMORY */
/* All fields are cleared; nonzero fields are reinitialized in appropriate function */
memset(&btm_cb, 0, sizeof(tBTM_CB));
btm_cb.page_queue = fixed_queue_new(QUEUE_SIZE_MAX);
btm_cb.sec_pending_q = fixed_queue_new(QUEUE_SIZE_MAX);
#if defined(BTM_INITIAL_TRACE_LEVEL)
btm_cb.trace_level = BTM_INITIAL_TRACE_LEVEL;
#else
btm_cb.trace_level = BT_TRACE_LEVEL_NONE;
#endif
/* Initialize BTM component structures */
btm_inq_db_init(); /* Inquiry Database and Structures */
btm_acl_init(); /* ACL Database and Structures */
#if (SMP_INCLUDED == TRUE)
btm_sec_init(BTM_SEC_MODE_SP); /* Security Manager Database and Structures */
#endif ///SMP_INCLUDED == TRUE
#if BTM_SCO_INCLUDED == TRUE
btm_sco_init(); /* SCO Database and Structures (If included) */
#endif
btm_dev_init(); /* Device Manager Structures & HCI_Reset */
#if BLE_INCLUDED == TRUE
btm_ble_lock_init();
btm_ble_sem_init();
#endif
btm_sec_dev_init();
#if (BLE_50_FEATURE_SUPPORT == TRUE)
btm_ble_extendadvcb_init();
btm_ble_advrecod_init();
#endif
}
/*******************************************************************************
**
** Function btm_free
**
** Description This function is called at btu core free the fixed queue
**
** Returns void
**
*******************************************************************************/
void btm_free(void)
{
fixed_queue_free(btm_cb.page_queue, osi_free_func);
fixed_queue_free(btm_cb.sec_pending_q, osi_free_func);
btm_acl_free();
btm_sec_dev_free();
#if BTM_DYNAMIC_MEMORY
FREE_AND_RESET(btm_cb_ptr);
#endif
#if BLE_INCLUDED == TRUE
btm_ble_lock_free();
btm_ble_sem_free();
#endif
}
uint8_t btm_acl_active_count(void)
{
list_node_t *p_node = NULL;
tACL_CONN *p_acl_conn = NULL;
uint8_t count = 0;
for (p_node = list_begin(btm_cb.p_acl_db_list); p_node; p_node = list_next(p_node)) {
p_acl_conn = list_node(p_node);
if (p_acl_conn && p_acl_conn->in_use) {
count++;
}
}
return count;
}
uint8_t btdm_sec_dev_active_count(void)
{
tBTM_SEC_DEV_REC *p_dev_rec = NULL;
list_node_t *p_node = NULL;
uint8_t count = 0;
/* First look for the non-paired devices for the oldest entry */
for (p_node = list_begin(btm_cb.p_sec_dev_rec_list); p_node; p_node = list_next(p_node)) {
p_dev_rec = list_node(p_node);
if (p_dev_rec && (p_dev_rec->sec_flags & BTM_SEC_IN_USE)) {
count++;
}
}
return count;
}
+965
View File
@@ -0,0 +1,965 @@
/******************************************************************************
*
* Copyright (C) 2000-2012 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.
*
******************************************************************************/
/*****************************************************************************
*
* This file contains functions that manages ACL link modes.
* This includes operations such as active, hold,
* park and sniff modes.
*
* This module contains both internal and external (API)
* functions. External (API) functions are distinguishable
* by their names beginning with uppercase BTM.
*
*****************************************************************************/
//#define LOG_TAG "bt_btm_pm"
#include <stdlib.h>
#include <string.h>
//#include <stdio.h>
#include <stddef.h>
#include "stack/bt_types.h"
#include "stack/hcimsgs.h"
#include "stack/btu.h"
#include "stack/btm_api.h"
#include "btm_int.h"
#include "l2c_int.h"
#include "stack/hcidefs.h"
//#include "bt_utils.h"
//#include "osi/include/log.h"
#include "osi/allocator.h"
/*****************************************************************************/
/* to handle different modes */
/*****************************************************************************/
#define BTM_PM_STORED_MASK 0x80 /* set this mask if the command is stored */
#define BTM_PM_NUM_SET_MODES 3 /* only hold, sniff & park */
/* Usage: (ptr_features[ offset ] & mask )?TRUE:FALSE */
/* offset to supported feature */
const UINT8 btm_pm_mode_off[BTM_PM_NUM_SET_MODES] = {0, 0, 1};
/* mask to supported feature */
const UINT8 btm_pm_mode_msk[BTM_PM_NUM_SET_MODES] = {0x40, 0x80, 0x01};
#define BTM_PM_GET_MD1 1
#define BTM_PM_GET_MD2 2
#define BTM_PM_GET_COMP 3
const UINT8 btm_pm_md_comp_matrix[BTM_PM_NUM_SET_MODES * BTM_PM_NUM_SET_MODES] = {
BTM_PM_GET_COMP,
BTM_PM_GET_MD2,
BTM_PM_GET_MD2,
BTM_PM_GET_MD1,
BTM_PM_GET_COMP,
BTM_PM_GET_MD1,
BTM_PM_GET_MD1,
BTM_PM_GET_MD2,
BTM_PM_GET_COMP
};
/* function prototype */
static tBTM_STATUS btm_pm_snd_md_req( UINT8 pm_id, UINT16 link_hdl, tBTM_PM_PWR_MD *p_mode );
#if (!CONFIG_BT_STACK_NO_LOG)
static const char *mode_to_string(tBTM_PM_MODE mode);
#endif
/*
#ifdef BTM_PM_DEBUG
#undef BTM_PM_DEBUG
#define BTM_PM_DEBUG TRUE
#endif
*/
#if BTM_PM_DEBUG == TRUE
const char *btm_pm_state_str[] = {
"pm_active_state",
"pm_hold_state",
"pm_sniff_state",
"pm_park_state",
"pm_pend_state"
};
const char *btm_pm_event_str[] = {
"pm_set_mode_event",
"pm_hci_sts_event",
"pm_mod_chg_event",
"pm_update_event"
};
const char *btm_pm_action_str[] = {
"pm_set_mode_action",
"pm_update_db_action",
"pm_mod_chg_action",
"pm_hci_sts_action",
"pm_update_action"
};
#endif // BTM_PM_DEBUG
/*****************************************************************************/
/* P U B L I C F U N C T I O N S */
/*****************************************************************************/
/*******************************************************************************
**
** Function BTM_PmRegister
**
** Description register or deregister with power manager
**
** Returns BTM_SUCCESS if successful,
** BTM_NO_RESOURCES if no room to hold registration
** BTM_ILLEGAL_VALUE
**
*******************************************************************************/
tBTM_STATUS BTM_PmRegister (UINT8 mask, UINT8 *p_pm_id, tBTM_PM_STATUS_CBACK *p_cb)
{
int xx;
/* de-register */
if (mask & BTM_PM_DEREG) {
if (*p_pm_id >= BTM_MAX_PM_RECORDS) {
return BTM_ILLEGAL_VALUE;
}
btm_cb.pm_reg_db[*p_pm_id].mask = BTM_PM_REC_NOT_USED;
return BTM_SUCCESS;
}
for (xx = 0; xx < BTM_MAX_PM_RECORDS; xx++) {
/* find an unused entry */
if (btm_cb.pm_reg_db[xx].mask == BTM_PM_REC_NOT_USED) {
/* if register for notification, should provide callback routine */
if (mask & BTM_PM_REG_NOTIF) {
if (p_cb == NULL) {
return BTM_ILLEGAL_VALUE;
}
btm_cb.pm_reg_db[xx].cback = p_cb;
}
btm_cb.pm_reg_db[xx].mask = mask;
*p_pm_id = xx;
return BTM_SUCCESS;
}
}
return BTM_NO_RESOURCES;
}
/*******************************************************************************
**
** Function BTM_SetPowerMode
**
** Description store the mode in control block or
** alter ACL connection behavior.
**
** Returns BTM_SUCCESS if successful,
** BTM_UNKNOWN_ADDR if bd addr is not active or bad
**
*******************************************************************************/
tBTM_STATUS BTM_SetPowerMode (UINT8 pm_id, BD_ADDR remote_bda, tBTM_PM_PWR_MD *p_mode)
{
UINT8 *p_features;
int ind;
tBTM_PM_MCB *p_cb = NULL; /* per ACL link */
tBTM_PM_MODE mode;
int temp_pm_id;
tACL_CONN *p_acl_cb;
if (pm_id >= BTM_MAX_PM_RECORDS) {
pm_id = BTM_PM_SET_ONLY_ID;
}
if (p_mode == NULL) {
return BTM_ILLEGAL_VALUE;
}
BTM_TRACE_API( "BTM_SetPowerMode: pm_id %d BDA: %08x mode:0x%x", pm_id,
(remote_bda[2] << 24) + (remote_bda[3] << 16) + (remote_bda[4] << 8) + remote_bda[5], p_mode->mode);
/* take out the force bit */
mode = p_mode->mode & ~BTM_PM_MD_FORCE;
p_acl_cb = btm_bda_to_acl(remote_bda, BT_TRANSPORT_BR_EDR);
if (p_acl_cb == NULL){
return BTM_UNKNOWN_ADDR;
}
p_cb = p_acl_cb->p_pm_mode_db;
if (mode != BTM_PM_MD_ACTIVE) {
/* check if the requested mode is supported */
ind = mode - BTM_PM_MD_HOLD; /* make it base 0 */
p_features = BTM_ReadLocalFeatures();
if ( !(p_features[ btm_pm_mode_off[ind] ] & btm_pm_mode_msk[ind] ) ) {
return BTM_MODE_UNSUPPORTED;
}
}
if (mode == p_cb->state) { /* the requested mode is current mode */
/* already in the requested mode and the current interval has less latency than the max */
if ( (mode == BTM_PM_MD_ACTIVE) ||
((p_mode->mode & BTM_PM_MD_FORCE) && (p_mode->max >= p_cb->interval) && (p_mode->min <= p_cb->interval)) ||
((p_mode->mode & BTM_PM_MD_FORCE) == 0 && (p_mode->max >= p_cb->interval)) ) {
BTM_TRACE_DEBUG( "BTM_SetPowerMode: mode:0x%x interval %d max:%d, min:%d", p_mode->mode, p_cb->interval, p_mode->max, p_mode->min);
return BTM_SUCCESS;
}
}
temp_pm_id = pm_id;
if (pm_id == BTM_PM_SET_ONLY_ID) {
temp_pm_id = BTM_MAX_PM_RECORDS;
}
/* update mode database */
if ( ((pm_id != BTM_PM_SET_ONLY_ID) &&
(btm_cb.pm_reg_db[pm_id].mask & BTM_PM_REG_SET))
|| ((pm_id == BTM_PM_SET_ONLY_ID)
&& (btm_cb.pm_pend_link_hdl != BTM_INVALID_HANDLE)) ) {
#if BTM_PM_DEBUG == TRUE
BTM_TRACE_DEBUG( "BTM_SetPowerMode: Saving cmd acl handle %d temp_pm_id %d", p_acl_cb->hci_handle, temp_pm_id);
#endif // BTM_PM_DEBUG
/* Make sure mask is set to BTM_PM_REG_SET */
btm_cb.pm_reg_db[temp_pm_id].mask |= BTM_PM_REG_SET;
*(&p_cb->req_mode[temp_pm_id]) = *((tBTM_PM_PWR_MD *)p_mode);
p_cb->chg_ind = TRUE;
}
#if BTM_PM_DEBUG == TRUE
BTM_TRACE_DEBUG( "btm_pm state:0x%x, pm_pend_link_hdl: %d", p_cb->state, btm_cb.pm_pend_link_hdl);
#endif // BTM_PM_DEBUG
/* if mode == hold or pending, return */
if ( (p_cb->state == BTM_PM_STS_HOLD) ||
(p_cb->state == BTM_PM_STS_PENDING) ||
(btm_cb.pm_pend_link_hdl != BTM_INVALID_HANDLE) ||
(p_cb->state & BTM_PM_STORED_MASK) ) { /* command pending */
if (p_acl_cb->hci_handle != btm_cb.pm_pend_link_hdl) {
/* set the stored mask */
p_cb->state |= BTM_PM_STORED_MASK;
BTM_TRACE_DEBUG( "btm_pm state stored:%d", p_acl_cb->hci_handle);
}
return BTM_CMD_STORED;
}
return btm_pm_snd_md_req(pm_id, p_acl_cb->hci_handle, p_mode);
}
/*******************************************************************************
**
** Function BTM_ReadPowerMode
**
** Description This returns the current mode for a specific
** ACL connection.
**
** Input Param remote_bda - device address of desired ACL connection
**
** Output Param p_mode - address where the current mode is copied into.
** BTM_ACL_MODE_NORMAL
** BTM_ACL_MODE_HOLD
** BTM_ACL_MODE_SNIFF
** BTM_ACL_MODE_PARK
** (valid only if return code is BTM_SUCCESS)
**
** Returns BTM_SUCCESS if successful,
** BTM_UNKNOWN_ADDR if bd addr is not active or bad
**
*******************************************************************************/
tBTM_STATUS BTM_ReadPowerMode (BD_ADDR remote_bda, tBTM_PM_MODE *p_mode)
{
tACL_CONN *p_acl_cb = btm_bda_to_acl(remote_bda, BT_TRANSPORT_BR_EDR);
if (!p_acl_cb) {
return (BTM_UNKNOWN_ADDR);
}
*p_mode = p_acl_cb->p_pm_mode_db->state;
return BTM_SUCCESS;
}
/*******************************************************************************
**
** Function BTM_SetSsrParams
**
** Description This sends the given SSR parameters for the given ACL
** connection if it is in ACTIVE mode.
**
** Input Param remote_bda - device address of desired ACL connection
** max_lat - maximum latency (in 0.625ms)(0-0xFFFE)
** min_rmt_to - minimum remote timeout
** min_loc_to - minimum local timeout
**
**
** Returns BTM_SUCCESS if the HCI command is issued successful,
** BTM_UNKNOWN_ADDR if bd addr is not active or bad
** BTM_CMD_STORED if the command is stored
**
*******************************************************************************/
tBTM_STATUS BTM_SetSsrParams (BD_ADDR remote_bda, UINT16 max_lat,
UINT16 min_rmt_to, UINT16 min_loc_to)
{
#if (BTM_SSR_INCLUDED == TRUE)
tBTM_PM_MCB *p_cb;
tACL_CONN *p_acl_cb = NULL;
p_acl_cb = btm_bda_to_acl(remote_bda, BT_TRANSPORT_BR_EDR);
if (!p_acl_cb) {
return (BTM_UNKNOWN_ADDR);
}
p_cb = p_acl_cb->p_pm_mode_db;
if (BTM_PM_STS_ACTIVE == p_cb->state ||
BTM_PM_STS_SNIFF == p_cb->state) {
if (btsnd_hcic_sniff_sub_rate(p_acl_cb->hci_handle, max_lat,
min_rmt_to, min_loc_to)) {
return BTM_SUCCESS;
} else {
return BTM_NO_RESOURCES;
}
}
p_cb->max_lat = max_lat;
p_cb->min_rmt_to = min_rmt_to;
p_cb->min_loc_to = min_loc_to;
return BTM_CMD_STORED;
#else
return BTM_ILLEGAL_ACTION;
#endif // BTM_SSR_INCLUDED
}
/*******************************************************************************
**
** Function btm_pm_reset
**
** Description as a part of the BTM reset process.
**
** Returns void
**
*******************************************************************************/
void btm_pm_reset(void)
{
int xx;
tBTM_PM_STATUS_CBACK *cb = NULL;
/* clear the pending request for application */
if ( (btm_cb.pm_pend_id != BTM_PM_SET_ONLY_ID) &&
(btm_cb.pm_reg_db[btm_cb.pm_pend_id].mask & BTM_PM_REG_NOTIF) ) {
cb = btm_cb.pm_reg_db[btm_cb.pm_pend_id].cback;
}
/* clear the register record */
for (xx = 0; xx < BTM_MAX_PM_RECORDS; xx++) {
btm_cb.pm_reg_db[xx].mask = BTM_PM_REC_NOT_USED;
}
if (cb != NULL && btm_cb.pm_pend_link_hdl != BTM_INVALID_HANDLE) {
(*cb)((btm_handle_to_acl(btm_cb.pm_pend_link_hdl))->remote_addr, BTM_PM_STS_ERROR, BTM_DEV_RESET, 0);
}
/* no command pending */
btm_cb.pm_pend_link_hdl = BTM_INVALID_HANDLE;
}
/*******************************************************************************
**
** Function btm_pm_sm_alloc
**
** Description This function initializes the control block of an ACL link.
** It is called when an ACL connection is created.
**
** Returns void
**
*******************************************************************************/
tBTM_PM_MCB *btm_pm_sm_alloc(void)
{
tBTM_PM_MCB *p_db = (tBTM_PM_MCB *) osi_malloc(sizeof(tBTM_PM_MCB)); /* per ACL link */
if (p_db) {
memset (p_db, 0, sizeof(tBTM_PM_MCB));
p_db->state = BTM_PM_ST_ACTIVE;
if (list_length(btm_cb.p_pm_mode_db_list) >= MAX_L2CAP_LINKS) {
osi_free(p_db);
p_db = NULL;
}
if (!list_append(btm_cb.p_pm_mode_db_list, p_db)) {
osi_free(p_db);
p_db = NULL;
}
}
return p_db;
}
/*******************************************************************************
**
** Function btm_pm_find_acl_ind
**
** Description This function initializes the control block of an ACL link.
** It is called when an ACL connection is created.
**
** Returns void
**
*******************************************************************************/
/*******************************************************************************
**
** Function btm_pm_compare_modes
** Description get the "more active" mode of the 2
** Returns void
**
*******************************************************************************/
static tBTM_PM_PWR_MD *btm_pm_compare_modes(tBTM_PM_PWR_MD *p_md1, tBTM_PM_PWR_MD *p_md2, tBTM_PM_PWR_MD *p_res)
{
UINT8 res;
if (p_md1 == NULL) {
*p_res = *p_md2;
p_res->mode &= ~BTM_PM_MD_FORCE;
return p_md2;
}
if (p_md2->mode == BTM_PM_MD_ACTIVE || p_md1->mode == BTM_PM_MD_ACTIVE) {
return NULL;
}
/* check if force bit is involved */
if (p_md1->mode & BTM_PM_MD_FORCE) {
*p_res = *p_md1;
p_res->mode &= ~BTM_PM_MD_FORCE;
return p_res;
}
if (p_md2->mode & BTM_PM_MD_FORCE) {
*p_res = *p_md2;
p_res->mode &= ~BTM_PM_MD_FORCE;
return p_res;
}
res = (p_md1->mode - 1) * BTM_PM_NUM_SET_MODES + (p_md2->mode - 1);
res = btm_pm_md_comp_matrix[res];
switch (res) {
case BTM_PM_GET_MD1:
*p_res = *p_md1;
return p_md1;
case BTM_PM_GET_MD2:
*p_res = *p_md2;
return p_md2;
case BTM_PM_GET_COMP:
p_res->mode = p_md1->mode;
/* min of the two */
p_res->max = (p_md1->max < p_md2->max) ? (p_md1->max) : (p_md2->max);
/* max of the two */
p_res->min = (p_md1->min > p_md2->min) ? (p_md1->min) : (p_md2->min);
/* the intersection is NULL */
if ( p_res->max < p_res->min) {
return NULL;
}
if (p_res->mode == BTM_PM_MD_SNIFF) {
/* max of the two */
p_res->attempt = (p_md1->attempt > p_md2->attempt) ? (p_md1->attempt) : (p_md2->attempt);
p_res->timeout = (p_md1->timeout > p_md2->timeout) ? (p_md1->timeout) : (p_md2->timeout);
}
return p_res;
}
return NULL;
}
/*******************************************************************************
**
** Function btm_pm_get_set_mode
** Description get the resulting mode from the registered parties, then compare it
** with the requested mode, if the command is from an unregistered party.
** Returns void
**
*******************************************************************************/
static tBTM_PM_MODE btm_pm_get_set_mode(UINT8 pm_id, tBTM_PM_MCB *p_cb, tBTM_PM_PWR_MD *p_mode, tBTM_PM_PWR_MD *p_res)
{
int xx, loop_max;
tBTM_PM_PWR_MD *p_md = NULL;
if (p_mode != NULL && p_mode->mode & BTM_PM_MD_FORCE) {
*p_res = *p_mode;
p_res->mode &= ~BTM_PM_MD_FORCE;
return p_res->mode;
}
if (!p_mode) {
loop_max = BTM_MAX_PM_RECORDS + 1;
} else {
loop_max = BTM_MAX_PM_RECORDS;
}
for ( xx = 0; xx < loop_max; xx++) {
/* g through all the registered "set" parties */
if (btm_cb.pm_reg_db[xx].mask & BTM_PM_REG_SET) {
if (p_cb->req_mode[xx].mode == BTM_PM_MD_ACTIVE) {
/* if at least one registered (SET) party says ACTIVE, stay active */
return BTM_PM_MD_ACTIVE;
} else {
/* if registered parties give conflicting information, stay active */
if ( (btm_pm_compare_modes(p_md, &p_cb->req_mode[xx], p_res)) == NULL) {
return BTM_PM_MD_ACTIVE;
}
p_md = p_res;
}
}
}
/* if the resulting mode is NULL(nobody registers SET), use the requested mode */
if (p_md == NULL) {
if (p_mode) {
*p_res = *((tBTM_PM_PWR_MD *)p_mode);
} else { /* p_mode is NULL when btm_pm_snd_md_req is called from btm_pm_proc_mode_change */
return BTM_PM_MD_ACTIVE;
}
} else {
/* if the command is from unregistered party,
compare the resulting mode from registered party*/
if ( (pm_id == BTM_PM_SET_ONLY_ID) &&
((btm_pm_compare_modes(p_mode, p_md, p_res)) == NULL) ) {
return BTM_PM_MD_ACTIVE;
}
}
return p_res->mode;
}
/*******************************************************************************
**
** Function btm_pm_snd_md_req
** Description get the resulting mode and send the resuest to host controller
** Returns tBTM_STATUS
**, BOOLEAN *p_chg_ind
*******************************************************************************/
static tBTM_STATUS btm_pm_snd_md_req(UINT8 pm_id, UINT16 link_hdl, tBTM_PM_PWR_MD *p_mode)
{
tBTM_PM_PWR_MD md_res;
tBTM_PM_MODE mode;
tACL_CONN *p_acl_cb = btm_handle_to_acl(link_hdl);
tBTM_PM_MCB *p_cb = p_acl_cb->p_pm_mode_db;
BOOLEAN chg_ind = FALSE;
mode = btm_pm_get_set_mode(pm_id, p_cb, p_mode, &md_res);
md_res.mode = mode;
#if BTM_PM_DEBUG == TRUE
BTM_TRACE_DEBUG( "btm_pm_snd_md_req link_hdl:%d, mode: %d",
link_hdl, mode);
#endif // BTM_PM_DEBUG
if ( p_cb->state == mode) {
/* already in the resulting mode */
if ( (mode == BTM_PM_MD_ACTIVE) ||
((md_res.max >= p_cb->interval) && (md_res.min <= p_cb->interval)) ) {
return BTM_CMD_STORED;
}
/* Otherwise, needs to wake, then sleep */
chg_ind = TRUE;
}
p_cb->chg_ind = chg_ind;
/* cannot go directly from current mode to resulting mode. */
if ( mode != BTM_PM_MD_ACTIVE && p_cb->state != BTM_PM_MD_ACTIVE) {
p_cb->chg_ind = TRUE; /* needs to wake, then sleep */
}
if (p_cb->chg_ind == TRUE) { /* needs to wake first */
md_res.mode = BTM_PM_MD_ACTIVE;
}
#if (BTM_SSR_INCLUDED == TRUE)
else if (BTM_PM_MD_SNIFF == md_res.mode && p_cb->max_lat) {
btsnd_hcic_sniff_sub_rate(link_hdl, p_cb->max_lat,
p_cb->min_rmt_to, p_cb->min_loc_to);
p_cb->max_lat = 0;
}
#endif // BTM_SSR_INCLUDED
/* Default is failure */
btm_cb.pm_pend_link_hdl = BTM_INVALID_HANDLE;
/* send the appropriate HCI command */
btm_cb.pm_pend_id = pm_id;
#if BTM_PM_DEBUG == TRUE
BTM_TRACE_DEBUG("btm_pm_snd_md_req state:0x%x, link_hdl: %d", p_cb->state, link_hdl);
#endif // BTM_PM_DEBUG
BTM_TRACE_DEBUG("%s switching from %s to %s.", __func__, mode_to_string(p_cb->state), mode_to_string(md_res.mode));
switch (md_res.mode) {
case BTM_PM_MD_ACTIVE:
switch (p_cb->state) {
case BTM_PM_MD_SNIFF:
if (btsnd_hcic_exit_sniff_mode(link_hdl)) {
btm_cb.pm_pend_link_hdl = link_hdl;
}
break;
case BTM_PM_MD_PARK:
if (btsnd_hcic_exit_park_mode(link_hdl)) {
btm_cb.pm_pend_link_hdl = link_hdl;
}
break;
default:
/* Failure btm_cb.pm_pend_link = MAX_L2CAP_LINKS */
break;
}
break;
case BTM_PM_MD_HOLD:
if (btsnd_hcic_hold_mode (link_hdl,
md_res.max, md_res.min)) {
btm_cb.pm_pend_link_hdl = link_hdl;
}
break;
case BTM_PM_MD_SNIFF:
if (btsnd_hcic_sniff_mode (link_hdl,
md_res.max, md_res.min, md_res.attempt,
md_res.timeout)) {
btm_cb.pm_pend_link_hdl = link_hdl;
}
break;
case BTM_PM_MD_PARK:
if (btsnd_hcic_park_mode (link_hdl,
md_res.max, md_res.min)) {
btm_cb.pm_pend_link_hdl = link_hdl;
}
break;
default:
/* Failure btm_cb.pm_pend_link = MAX_L2CAP_LINKS */
break;
}
if (btm_cb.pm_pend_link_hdl == BTM_INVALID_HANDLE) {
/* the command was not sent */
#if BTM_PM_DEBUG == TRUE
BTM_TRACE_DEBUG( "pm_pend_link_hdl: %d", btm_cb.pm_pend_link_hdl);
#endif // BTM_PM_DEBUG
return (BTM_NO_RESOURCES);
}
return BTM_CMD_STARTED;
}
/*******************************************************************************
**
** Function btm_pm_check_stored
**
** Description This function is called when an HCI command status event occurs
** to check if there's any PM command issued while waiting for
** HCI command status.
**
** Returns none.
**
*******************************************************************************/
static void btm_pm_check_stored(void)
{
tACL_CONN *p_acl_cb = NULL;
list_node_t *p_node = NULL;
for (p_node = list_begin(btm_cb.p_acl_db_list); p_node; p_node = list_next(p_node)) {
p_acl_cb = list_node(p_node);
if (p_acl_cb->p_pm_mode_db->state & BTM_PM_STORED_MASK) {
p_acl_cb->p_pm_mode_db->state &= ~BTM_PM_STORED_MASK;
BTM_TRACE_DEBUG( "btm_pm_check_stored :%d", p_acl_cb->hci_handle);
btm_pm_snd_md_req(BTM_PM_SET_ONLY_ID, p_acl_cb->hci_handle, NULL);
break;
}
}
}
/*******************************************************************************
**
** Function btm_pm_proc_cmd_status
**
** Description This function is called when an HCI command status event occurs
** for power manager related commands.
**
** Input Parms status - status of the event (HCI_SUCCESS if no errors)
**
** Returns none.
**
*******************************************************************************/
void btm_pm_proc_cmd_status(UINT8 status)
{
tBTM_PM_MCB *p_cb;
tBTM_PM_STATUS pm_status;
tACL_CONN *p_acl_cb;
if (btm_cb.pm_pend_link_hdl == BTM_INVALID_HANDLE) {
return;
}
p_acl_cb = btm_handle_to_acl(btm_cb.pm_pend_link_hdl);
if (p_acl_cb == NULL) {
return;
}
p_cb = p_acl_cb->p_pm_mode_db;
if (status == HCI_SUCCESS) {
p_cb->state = BTM_PM_ST_PENDING;
pm_status = BTM_PM_STS_PENDING;
#if BTM_PM_DEBUG == TRUE
BTM_TRACE_DEBUG( "btm_pm_proc_cmd_status new state:0x%x", p_cb->state);
#endif // BTM_PM_DEBUG
} else { /* the command was not successfull. Stay in the same state */
pm_status = BTM_PM_STS_ERROR;
}
/* notify the caller is appropriate */
if ( (btm_cb.pm_pend_id != BTM_PM_SET_ONLY_ID) &&
(btm_cb.pm_reg_db[btm_cb.pm_pend_id].mask & BTM_PM_REG_NOTIF) ) {
(*btm_cb.pm_reg_db[btm_cb.pm_pend_id].cback)(p_acl_cb->remote_addr, pm_status, 0, status);
}
/* no pending cmd now */
#if BTM_PM_DEBUG == TRUE
BTM_TRACE_DEBUG( "btm_pm_proc_cmd_status state:0x%x, pm_pend_link: %d(new: %d)",
p_cb->state, btm_cb.pm_pend_link_hdl, MAX_L2CAP_LINKS);
#endif // BTM_PM_DEBUG
btm_cb.pm_pend_link_hdl = BTM_INVALID_HANDLE;
btm_pm_check_stored();
}
/*******************************************************************************
**
** Function btm_process_mode_change
**
** Description This function is called when an HCI mode change event occurs.
**
** Input Parms hci_status - status of the event (HCI_SUCCESS if no errors)
** hci_handle - connection handle associated with the change
** mode - HCI_MODE_ACTIVE, HCI_MODE_HOLD, HCI_MODE_SNIFF, or HCI_MODE_PARK
** interval - number of baseband slots (meaning depends on mode)
**
** Returns none.
**
*******************************************************************************/
void btm_pm_proc_mode_change (UINT8 hci_status, UINT16 hci_handle, UINT8 mode, UINT16 interval)
{
tACL_CONN *p;
tBTM_PM_MCB *p_cb = NULL;
int yy;
tBTM_PM_STATE old_state;
tL2C_LCB *p_lcb;
/* get the index to acl_db */
p = btm_handle_to_acl(hci_handle);
if (!p) {
return;
}
/* update control block */
p_cb = p->p_pm_mode_db;
old_state = p_cb->state;
p_cb->state = mode;
p_cb->interval = interval;
BTM_TRACE_DEBUG("%s switched from %s to %s.", __func__, mode_to_string(old_state), mode_to_string(p_cb->state));
if ((p_lcb = l2cu_find_lcb_by_bd_addr(p->remote_addr, BT_TRANSPORT_BR_EDR)) != NULL) {
if ((p_cb->state == BTM_PM_ST_ACTIVE) || (p_cb->state == BTM_PM_ST_SNIFF)) {
/* There might be any pending packets due to SNIFF or PENDING state */
/* Trigger L2C to start transmission of the pending packets. */
BTM_TRACE_DEBUG("btm mode change to active; check l2c_link for outgoing packets");
l2c_link_check_send_pkts(p_lcb, NULL, NULL);
}
}
/* notify registered parties */
for (yy = 0; yy <= BTM_MAX_PM_RECORDS; yy++) {
/* set req_mode HOLD mode->ACTIVE */
if ( (mode == BTM_PM_MD_ACTIVE) && (p_cb->req_mode[yy].mode == BTM_PM_MD_HOLD) ) {
p_cb->req_mode[yy].mode = BTM_PM_MD_ACTIVE;
}
}
/* new request has been made. - post a message to BTU task */
if (old_state & BTM_PM_STORED_MASK) {
#if BTM_PM_DEBUG == TRUE
BTM_TRACE_DEBUG( "btm_pm_proc_mode_change: Sending stored req:%d", xx);
#endif // BTM_PM_DEBUG
btm_pm_snd_md_req(BTM_PM_SET_ONLY_ID, hci_handle, NULL);
} else {
list_node_t *p_node = NULL;
for (p_node =(list_begin(btm_cb.p_pm_mode_db_list)); p_node; p_node = (list_next(p_node))) {
p_cb = (tBTM_PM_MCB *)list_node(p_node);
if (p_cb->chg_ind == TRUE) {
#if BTM_PM_DEBUG == TRUE
BTM_TRACE_DEBUG( "btm_pm_proc_mode_change: Sending PM req :%d", zz);
#endif // BTM_PM_DEBUG
btm_pm_snd_md_req(BTM_PM_SET_ONLY_ID, hci_handle, NULL);
break;
}
}
}
/* notify registered parties */
for (yy = 0; yy < BTM_MAX_PM_RECORDS; yy++) {
if (btm_cb.pm_reg_db[yy].mask & BTM_PM_REG_NOTIF) {
(*btm_cb.pm_reg_db[yy].cback)( p->remote_addr, mode, interval, hci_status);
}
}
/* If mode change was because of an active role switch or change link key */
btm_cont_rswitch(p, btm_find_dev(p->remote_addr), hci_status);
}
/*******************************************************************************
**
** Function btm_pm_proc_ssr_evt
**
** Description This function is called when an HCI sniff subrating event occurs.
**
** Returns none.
**
*******************************************************************************/
#if (BTM_SSR_INCLUDED == TRUE)
void btm_pm_proc_ssr_evt (UINT8 *p, UINT16 evt_len)
{
UINT8 status;
UINT16 handle;
UINT16 max_rx_lat;
int xx;
tBTM_PM_MCB *p_cb;
tACL_CONN *p_acl = NULL;
UINT16 use_ssr = TRUE;
UNUSED(evt_len);
STREAM_TO_UINT8 (status, p);
STREAM_TO_UINT16 (handle, p);
/* get the index to acl_db */
p += 2;
STREAM_TO_UINT16 (max_rx_lat, p);
p_acl = btm_handle_to_acl(handle);
if (!p_acl) {
return;
}
p_cb = p_acl->p_pm_mode_db;
if (p_cb->interval == max_rx_lat) {
/* using legacy sniff */
use_ssr = FALSE;
}
/* notify registered parties */
for (xx = 0; xx < BTM_MAX_PM_RECORDS; xx++) {
if (btm_cb.pm_reg_db[xx].mask & BTM_PM_REG_NOTIF) {
if ( p_acl) {
(*btm_cb.pm_reg_db[xx].cback)( p_acl->remote_addr, BTM_PM_STS_SSR, use_ssr, status);
}
}
}
}
#endif // BTM_SSR_INCLUDED
/*******************************************************************************
**
** Function btm_pm_device_in_active_or_sniff_mode
**
** Description This function is called to check if in active or sniff mode
**
** Returns TRUE, if in active or sniff mode
**
*******************************************************************************/
BOOLEAN btm_pm_device_in_active_or_sniff_mode(void)
{
/* The active state is the highest state-includes connected device and sniff mode*/
/* Covers active and sniff modes */
if (BTM_GetNumAclLinks() > 0) {
BTM_TRACE_DEBUG("%s - ACL links: %d", __func__, BTM_GetNumAclLinks());
return TRUE;
}
#if ((defined BLE_INCLUDED) && (BLE_INCLUDED == TRUE))
/* Check BLE states */
if (btm_ble_get_conn_st() != BLE_CONN_IDLE) {
BTM_TRACE_DEBUG("%s - BLE state: %x", __func__, btm_ble_get_conn_st());
return TRUE;
}
#endif
return FALSE;
}
/*******************************************************************************
**
** Function btm_pm_device_in_scan_state
**
** Description This function is called to check if in paging, inquiry or connecting mode
**
** Returns TRUE, if in paging, inquiry or connecting mode
**
*******************************************************************************/
BOOLEAN btm_pm_device_in_scan_state(void)
{
/* Scan state-paging, inquiry, and trying to connect */
/* Check for paging */
if (btm_cb.is_paging || (!fixed_queue_is_empty(btm_cb.page_queue)) ||
BTM_BL_PAGING_STARTED == btm_cb.busy_level) {
BTM_TRACE_DEBUG("btm_pm_device_in_scan_state- paging");
return TRUE;
}
/* Check for inquiry */
if ((btm_cb.btm_inq_vars.inq_active & (BTM_BR_INQ_ACTIVE_MASK | BTM_BLE_INQ_ACTIVE_MASK)) != 0) {
BTM_TRACE_DEBUG("btm_pm_device_in_scan_state- Inq active");
return TRUE;
}
return FALSE;
}
/*******************************************************************************
**
** Function BTM_PM_ReadControllerState
**
** Description This function is called to obtain the controller state
**
** Returns Controller State-BTM_CONTRL_ACTIVE, BTM_CONTRL_SCAN, and BTM_CONTRL_IDLE
**
*******************************************************************************/
tBTM_CONTRL_STATE BTM_PM_ReadControllerState(void)
{
if (TRUE == btm_pm_device_in_active_or_sniff_mode()) {
return BTM_CONTRL_ACTIVE;
} else if (TRUE == btm_pm_device_in_scan_state()) {
return BTM_CONTRL_SCAN;
} else {
return BTM_CONTRL_IDLE;
}
}
#if (!CONFIG_BT_STACK_NO_LOG)
static const char *mode_to_string(tBTM_PM_MODE mode)
{
switch (mode) {
case BTM_PM_MD_ACTIVE: return "ACTIVE";
case BTM_PM_MD_SNIFF: return "SNIFF";
case BTM_PM_MD_PARK: return "PARK";
case BTM_PM_MD_HOLD: return "HOLD";
default: return "UNKNOWN";
}
}
#endif
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,548 @@
/******************************************************************************
*
* Copyright (C) 1999-2012 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.
*
******************************************************************************/
/******************************************************************************
*
* this file contains the main Bluetooth Manager (BTM) internal
* definitions.
*
******************************************************************************/
#ifndef BTM_BLE_INT_H
#define BTM_BLE_INT_H
#include "common/bt_target.h"
#include "osi/fixed_queue.h"
#include "osi/pkt_queue.h"
#include "osi/thread.h"
#include "stack/hcidefs.h"
#include "stack/btm_ble_api.h"
#include "btm_int.h"
#if BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE
#include "stack/smp_api.h"
#endif
/* scanning enable status */
#define BTM_BLE_SCAN_ENABLE 0x01
#define BTM_BLE_SCAN_DISABLE 0x00
/* advertising enable status */
#define BTM_BLE_ADV_ENABLE 0x01
#define BTM_BLE_ADV_DISABLE 0x00
/* use the high 4 bits unused by inquiry mode */
#define BTM_BLE_SELECT_SCAN 0x20
#define BTM_BLE_NAME_REQUEST 0x40
#define BTM_BLE_OBSERVE 0x80
#define BTM_BLE_MAX_WL_ENTRY 1
#define BTM_BLE_AD_DATA_LEN 31
#define BTM_BLE_ENC_MASK 0x03
#define BTM_BLE_DUPLICATE_DISABLE 0
#define BTM_BLE_DUPLICATE_ENABLE 1
#define BTM_BLE_DUPLICATE_MAX BTM_BLE_DUPLICATE_ENABLE
#define BTM_BLE_GAP_DISC_SCAN_INT 18 /* Interval(scan_int) = 11.25 ms= 0x0010 * 0.625 ms */
#define BTM_BLE_GAP_DISC_SCAN_WIN 18 /* scan_window = 11.25 ms= 0x0010 * 0.625 ms */
#define BTM_BLE_GAP_ADV_INT 512 /* Tgap(gen_disc) = 1.28 s= 512 * 0.625 ms */
#define BTM_BLE_GAP_LIM_TOUT 180 /* Tgap(lim_timeout) = 180s max */
#define BTM_BLE_LOW_LATENCY_SCAN_INT 8000 /* Interval(scan_int) = 5s= 8000 * 0.625 ms */
#define BTM_BLE_LOW_LATENCY_SCAN_WIN 8000 /* scan_window = 5s= 8000 * 0.625 ms */
#define BTM_BLE_GAP_ADV_FAST_INT_1 48 /* TGAP(adv_fast_interval1) = 30(used) ~ 60 ms = 48 *0.625 */
#define BTM_BLE_GAP_ADV_FAST_INT_2 160 /* TGAP(adv_fast_interval2) = 100(used) ~ 150 ms = 160 * 0.625 ms */
#define BTM_BLE_GAP_ADV_SLOW_INT 2048 /* Tgap(adv_slow_interval) = 1.28 s= 512 * 0.625 ms */
#define BTM_BLE_GAP_ADV_DIR_MAX_INT 800 /* Tgap(dir_conn_adv_int_max) = 500 ms = 800 * 0.625 ms */
#define BTM_BLE_GAP_ADV_DIR_MIN_INT 400 /* Tgap(dir_conn_adv_int_min) = 250 ms = 400 * 0.625 ms */
#define BTM_BLE_GAP_FAST_ADV_TOUT 30
#define BTM_BLE_SEC_REQ_ACT_NONE 0
#define BTM_BLE_SEC_REQ_ACT_ENCRYPT 1 /* encrypt the link using current key or key refresh */
#define BTM_BLE_SEC_REQ_ACT_PAIR 2
#define BTM_BLE_SEC_REQ_ACT_DISCARD 3 /* discard the sec request while encryption is started but not completed */
typedef UINT8 tBTM_BLE_SEC_REQ_ACT;
#define BLE_STATIC_PRIVATE_MSB_MASK 0x3f
#define BLE_NON_RESOLVE_ADDR_MSB 0x00 /* most significant bit, bit7, bit6 is 00 to be non-resolvable random */
#define BLE_RESOLVE_ADDR_MSB 0x40 /* most significant bit, bit7, bit6 is 01 to be resolvable random */
#define BLE_RESOLVE_ADDR_MASK 0xc0 /* bit 6, and bit7 */
#define BTM_BLE_IS_NON_RESLVE_BDA(x) ((x[0] & BLE_RESOLVE_ADDR_MASK) == BLE_NON_RESOLVE_ADDR_MSB)
#define BTM_BLE_IS_RESOLVE_BDA(x) ((x[0] & BLE_RESOLVE_ADDR_MASK) == BLE_RESOLVE_ADDR_MSB)
/* LE scan activity bit mask, continue with LE inquiry bits */
#define BTM_LE_SELECT_CONN_ACTIVE 0x0040 /* selection connection is in progress */
#define BTM_LE_OBSERVE_ACTIVE 0x0080 /* observe is in progress */
#define BTM_LE_DISCOVER_ACTIVE 0x0100 /* scan is in progress */
/* BLE scan activity mask checking */
#define BTM_BLE_IS_SCAN_ACTIVE(x) ((x) & BTM_BLE_SCAN_ACTIVE_MASK)
#define BTM_BLE_IS_INQ_ACTIVE(x) ((x) & BTM_BLE_INQUIRY_MASK)
#define BTM_BLE_IS_OBS_ACTIVE(x) ((x) & BTM_LE_OBSERVE_ACTIVE)
#define BTM_BLE_IS_DISCO_ACTIVE(x) ((x) & BTM_LE_DISCOVER_ACTIVE)
#define BTM_BLE_IS_SEL_CONN_ACTIVE(x) ((x) & BTM_LE_SELECT_CONN_ACTIVE)
/* BLE ADDR type ID bit */
#define BLE_ADDR_TYPE_ID_BIT 0x02
#define BTM_VSC_CHIP_CAPABILITY_L_VERSION 55
#define BTM_VSC_CHIP_CAPABILITY_M_VERSION 95
typedef enum {
BTM_BLE_IDLE = 0,
BTM_BLE_SCANNING = 1,
BTM_BLE_ADVERTISING = 2,
}tBTM_BLE_GAP_STATE;
typedef struct {
UINT16 data_mask;
UINT8 *p_flags;
UINT8 ad_data[BTM_BLE_AD_DATA_LEN];
UINT8 *p_pad;
} tBTM_BLE_LOCAL_ADV_DATA;
typedef struct {
UINT32 inq_count; /* Used for determining if a response has already been */
/* received for the current inquiry operation. (We do not */
/* want to flood the caller with multiple responses from */
/* the same device. */
BOOLEAN scan_rsp;
tBLE_BD_ADDR le_bda;
} tINQ_LE_BDADDR;
#define BTM_BLE_ADV_DATA_LEN_MAX 31
#define BTM_BLE_CACHE_ADV_DATA_MAX 62
#if (BLE_50_FEATURE_SUPPORT == TRUE)
#define BTM_BLE_EXT_ADV_DATA_LEN_MAX 251
#define BTM_BLE_PERIODIC_ADV_DATA_LEN_MAX 252
#define BTM_BLE_ADV_DATA_OP_INTERMEDIATE_FRAG 0
#define BTM_BLE_ADV_DATA_OP_FIRST_FRAG 1
#define BTM_BLE_ADV_DATA_OP_LAST_FRAG 2
#define BTM_BLE_ADV_DATA_OP_COMPLETE 3
#define BTM_BLE_ADV_DATA_OP_UNCHANGED_DATA 4
#endif // #if (BLE_50_FEATURE_SUPPORT == TRUE)
#define BTM_BLE_ISVALID_PARAM(x, min, max) (((x) >= (min) && (x) <= (max)) || ((x) == BTM_BLE_CONN_PARAM_UNDEF))
typedef struct {
UINT16 discoverable_mode;
UINT16 connectable_mode;
BOOLEAN scan_params_set;
UINT32 scan_window;
UINT32 scan_interval;
UINT8 scan_type; /* current scan type: active or passive */
UINT8 scan_duplicate_filter; /* duplicate filter enabled for scan */
UINT16 adv_interval_min;
UINT16 adv_interval_max;
tBTM_BLE_AFP afp; /* advertising filter policy */
tBTM_BLE_SFP sfp; /* scanning filter policy */
tBTM_START_ADV_CMPL_CBACK *p_adv_cb;
tBTM_START_STOP_ADV_CMPL_CBACK *p_stop_adv_cb;
tBTM_CLEAR_ADV_CMPL_CBACK *p_clear_adv_cb;
tBLE_ADDR_TYPE adv_addr_type;
UINT8 evt_type;
UINT8 adv_mode;
tBLE_BD_ADDR direct_bda;
tBTM_BLE_EVT directed_conn;
BOOLEAN fast_adv_on;
TIMER_LIST_ENT fast_adv_timer;
UINT8 adv_len;
UINT8 adv_data_cache[BTM_BLE_CACHE_ADV_DATA_MAX];
BD_ADDR adv_addr;
/* inquiry BD addr database */
UINT8 num_bd_entries;
UINT8 max_bd_entries;
tBTM_BLE_LOCAL_ADV_DATA adv_data;
tBTM_BLE_ADV_CHNL_MAP adv_chnl_map;
TIMER_LIST_ENT inq_timer_ent;
BOOLEAN scan_rsp;
tBTM_BLE_GAP_STATE state; /* Current state that the adv or scan process is in */
INT8 tx_power;
} tBTM_BLE_INQ_CB;
/* random address resolving complete callback */
typedef void (tBTM_BLE_RESOLVE_CBACK) (void *match_rec, void *p);
typedef void (tBTM_BLE_ADDR_CBACK) (BD_ADDR_PTR static_random, void *p);
#define BTM_BLE_GAP_ADDR_BIT_RANDOM (1<<0)
#define BTM_BLE_GAP_ADDR_BIT_RESOLVABLE (1<<1)
/* random address management control block */
typedef struct {
tBLE_ADDR_TYPE own_addr_type; /* local device LE address type */
UINT8 exist_addr_bit;
BD_ADDR static_rand_addr;
BD_ADDR resolvale_addr;
BD_ADDR private_addr;
BD_ADDR random_bda;
BOOLEAN busy;
tBTM_SEC_DEV_REC *p_dev_rec;
tBTM_BLE_RESOLVE_CBACK *p_resolve_cback;
tBTM_BLE_ADDR_CBACK *p_generate_cback;
void *p;
TIMER_LIST_ENT raddr_timer_ent;
tBTM_SET_LOCAL_PRIVACY_CBACK *set_local_privacy_cback;
} tBTM_LE_RANDOM_CB;
#define BTM_BLE_MAX_BG_CONN_DEV_NUM 10
typedef struct {
UINT16 min_conn_int;
UINT16 max_conn_int;
UINT16 slave_latency;
UINT16 supervision_tout;
} tBTM_LE_CONN_PRAMS;
typedef struct {
BD_ADDR bd_addr;
UINT8 attr;
BOOLEAN is_connected;
BOOLEAN in_use;
} tBTM_LE_BG_CONN_DEV;
/* white list using state as a bit mask */
#define BTM_BLE_WL_IDLE 0
#define BTM_BLE_WL_INIT 1
#define BTM_BLE_WL_SCAN 2
#define BTM_BLE_WL_ADV 4
typedef UINT8 tBTM_BLE_WL_STATE;
/* resolving list using state as a bit mask */
#define BTM_BLE_RL_IDLE 0
#define BTM_BLE_RL_INIT 1
#define BTM_BLE_RL_SCAN 2
#define BTM_BLE_RL_ADV 4
typedef UINT8 tBTM_BLE_RL_STATE;
/* BLE connection state */
#define BLE_CONN_IDLE 0
#define BLE_DIR_CONN 1
#define BLE_BG_CONN 2
#define BLE_CONN_CANCEL 3
typedef UINT8 tBTM_BLE_CONN_ST;
typedef struct {
void *p_param;
} tBTM_BLE_CONN_REQ;
/* LE state request */
#define BTM_BLE_STATE_INVALID 0
#define BTM_BLE_STATE_CONN_ADV 1
#define BTM_BLE_STATE_INIT 2
#define BTM_BLE_STATE_MASTER 3
#define BTM_BLE_STATE_SLAVE 4
#define BTM_BLE_STATE_LO_DUTY_DIR_ADV 5
#define BTM_BLE_STATE_HI_DUTY_DIR_ADV 6
#define BTM_BLE_STATE_NON_CONN_ADV 7
#define BTM_BLE_STATE_PASSIVE_SCAN 8
#define BTM_BLE_STATE_ACTIVE_SCAN 9
#define BTM_BLE_STATE_SCAN_ADV 10
#define BTM_BLE_STATE_MAX 11
typedef UINT8 tBTM_BLE_STATE;
#define BTM_BLE_STATE_CONN_ADV_BIT 0x0001
#define BTM_BLE_STATE_INIT_BIT 0x0002
#define BTM_BLE_STATE_MASTER_BIT 0x0004
#define BTM_BLE_STATE_SLAVE_BIT 0x0008
#define BTM_BLE_STATE_LO_DUTY_DIR_ADV_BIT 0x0010
#define BTM_BLE_STATE_HI_DUTY_DIR_ADV_BIT 0x0020
#define BTM_BLE_STATE_NON_CONN_ADV_BIT 0x0040
#define BTM_BLE_STATE_PASSIVE_SCAN_BIT 0x0080
#define BTM_BLE_STATE_ACTIVE_SCAN_BIT 0x0100
#define BTM_BLE_STATE_SCAN_ADV_BIT 0x0200
typedef UINT16 tBTM_BLE_STATE_MASK;
#define BTM_BLE_STATE_ALL_MASK 0x03ff
#define BTM_BLE_STATE_ALL_ADV_MASK (BTM_BLE_STATE_CONN_ADV_BIT|BTM_BLE_STATE_LO_DUTY_DIR_ADV_BIT|BTM_BLE_STATE_HI_DUTY_DIR_ADV_BIT|BTM_BLE_STATE_SCAN_ADV_BIT)
#define BTM_BLE_STATE_ALL_SCAN_MASK (BTM_BLE_STATE_PASSIVE_SCAN_BIT|BTM_BLE_STATE_ACTIVE_SCAN_BIT)
#define BTM_BLE_STATE_ALL_CONN_MASK (BTM_BLE_STATE_MASTER_BIT|BTM_BLE_STATE_SLAVE_BIT)
#ifndef BTM_LE_RESOLVING_LIST_MAX
#define BTM_LE_RESOLVING_LIST_MAX 0x20
#endif
#define BTM_DUPLICATE_SCAN_EXCEPTIONAL_INFO_ADV_ADDR 0
#define BTM_DUPLICATE_SCAN_EXCEPTIONAL_INFO_MESH_LINK_ID 1
#define BTM_DUPLICATE_SCAN_EXCEPTIONAL_INFO_MESH_BEACON_TYPE 2
#define BTM_DUPLICATE_SCAN_EXCEPTIONAL_INFO_MESH_PROV_SRV_ADV 3
#define BTM_DUPLICATE_SCAN_EXCEPTIONAL_INFO_MESH_PROXY_SRV_ADV 4
typedef struct {
BD_ADDR *resolve_q_random_pseudo;
UINT8 *resolve_q_action;
UINT8 q_next;
UINT8 q_pending;
} tBTM_BLE_RESOLVE_Q;
typedef struct {
BOOLEAN in_use;
BOOLEAN to_add;
BD_ADDR bd_addr;
tBLE_ADDR_TYPE addr_type;
UINT8 attr;
} tBTM_BLE_WL_OP;
/* BLE privacy mode */
#define BTM_PRIVACY_NONE 0 /* BLE no privacy */
#define BTM_PRIVACY_1_1 1 /* BLE privacy 1.1, do not support privacy 1.0 */
#define BTM_PRIVACY_1_2 2 /* BLE privacy 1.2 */
#define BTM_PRIVACY_MIXED 3 /* BLE privacy mixed mode, broadcom propietary mode */
typedef UINT8 tBTM_PRIVACY_MODE;
/* data length change event callback */
typedef void (tBTM_DATA_LENGTH_CHANGE_CBACK) (UINT16 max_tx_length, UINT16 max_rx_length);
/* Define BLE Device Management control structure
*/
typedef struct {
UINT16 scan_activity; /* LE scan activity mask */
/*****************************************************
** BLE Inquiry
*****************************************************/
tBTM_BLE_INQ_CB inq_var;
/* observer callback and timer */
tBTM_INQ_RESULTS_CB *p_obs_results_cb;
tBTM_CMPL_CB *p_obs_cmpl_cb;
tBTM_INQ_DIS_CB *p_obs_discard_cb;
TIMER_LIST_ENT obs_timer_ent;
/* scan callback and timer */
tBTM_INQ_RESULTS_CB *p_scan_results_cb;
tBTM_CMPL_CB *p_scan_cmpl_cb;
TIMER_LIST_ENT scan_timer_ent;
struct pkt_queue *adv_rpt_queue;
struct osi_event *adv_rpt_ready;
/* background connection procedure cb value */
tBTM_BLE_CONN_TYPE bg_conn_type;
UINT32 scan_int;
UINT32 scan_win;
tBTM_BLE_SEL_CBACK *p_select_cback;
/* white list information */
UINT8 white_list_avail_size;
tBTM_UPDATE_WHITELIST_CBACK *update_wl_cb;
tBTM_BLE_WL_STATE wl_state;
fixed_queue_t *conn_pending_q;
tBTM_BLE_CONN_ST conn_state;
/* random address management control block */
tBTM_LE_RANDOM_CB addr_mgnt_cb;
BOOLEAN enabled;
#if BLE_PRIVACY_SPT == TRUE
BOOLEAN mixed_mode; /* privacy 1.2 mixed mode is on or not */
tBTM_PRIVACY_MODE privacy_mode; /* privacy mode */
UINT8 resolving_list_avail_size; /* resolving list available size */
tBTM_BLE_RESOLVE_Q resolving_list_pend_q; /* Resolving list queue */
tBTM_BLE_RL_STATE suspended_rl_state; /* Suspended resolving list state */
UINT8 *irk_list_mask; /* IRK list availability mask, up to max entry bits */
tBTM_BLE_RL_STATE rl_state; /* Resolving list state */
#endif
tBTM_BLE_WL_OP wl_op_q[BTM_BLE_MAX_BG_CONN_DEV_NUM];
/* current BLE link state */
tBTM_BLE_STATE_MASK cur_states; /* bit mask of tBTM_BLE_STATE */
UINT8 link_count[2]; /* total link count master and slave*/
tBTM_UPDATE_DUPLICATE_EXCEPTIONAL_LIST_CMPL_CBACK *update_exceptional_list_cmp_cb;
} tBTM_BLE_CB;
#ifdef __cplusplus
extern "C" {
#endif
void btm_ble_timeout(TIMER_LIST_ENT *p_tle);
void btm_ble_process_adv_pkt (UINT8 *p);
void btm_ble_process_adv_discard_evt(UINT8 *p);
void btm_ble_process_direct_adv_pkt (UINT8 *p);
bool btm_ble_adv_pkt_ready(void);
bool btm_ble_adv_pkt_post(pkt_linked_item_t *pkt);
void btm_ble_proc_scan_rsp_rpt (UINT8 *p);
tBTM_STATUS btm_ble_read_remote_name(BD_ADDR remote_bda, tBTM_INQ_INFO *p_cur, tBTM_CMPL_CB *p_cb);
BOOLEAN btm_ble_cancel_remote_name(BD_ADDR remote_bda);
tBTM_STATUS btm_ble_set_discoverability(UINT16 combined_mode);
tBTM_STATUS btm_ble_set_connectability(UINT16 combined_mode);
tBTM_STATUS btm_ble_start_inquiry (UINT8 mode, UINT8 duration);
void btm_ble_stop_scan(void);
void btm_clear_all_pending_le_entry(void);
BOOLEAN btm_ble_send_extended_scan_params(UINT8 scan_type, UINT32 scan_int, UINT32 scan_win, UINT8 addr_type_own, UINT8 scan_filter_policy);
void btm_ble_stop_inquiry(void);
void btm_ble_init (void);
void btm_ble_free (void);
void btm_ble_connected (UINT8 *bda, UINT16 handle, UINT8 enc_mode, UINT8 role, tBLE_ADDR_TYPE addr_type, BOOLEAN addr_matched);
void btm_ble_read_remote_features_complete(UINT8 *p);
void btm_ble_write_adv_enable_complete(UINT8 *p);
void btm_ble_conn_complete(UINT8 *p, UINT16 evt_len, BOOLEAN enhanced);
void btm_read_ble_local_supported_states_complete(UINT8 *p, UINT16 evt_len);
tBTM_BLE_CONN_ST btm_ble_get_conn_st(void);
void btm_ble_set_conn_st(tBTM_BLE_CONN_ST new_st);
UINT8 *btm_ble_build_adv_data(tBTM_BLE_AD_MASK *p_data_mask, UINT8 **p_dst, tBTM_BLE_ADV_DATA *p_data);
tBTM_STATUS btm_ble_start_adv(void);
tBTM_STATUS btm_ble_stop_adv(void);
tBTM_STATUS btm_ble_start_scan(void);
void btm_ble_create_ll_conn_complete (UINT8 status);
void btm_ble_create_conn_cancel_complete (UINT8 *p);
tBTM_STATUS btm_ble_set_random_addr(BD_ADDR random_bda);
/* LE security function from btm_sec.c */
#if SMP_INCLUDED == TRUE
void btm_ble_link_sec_check(BD_ADDR bd_addr, tBTM_LE_AUTH_REQ auth_req, tBTM_BLE_SEC_REQ_ACT *p_sec_req_act);
void btm_ble_ltk_request_reply(BD_ADDR bda, BOOLEAN use_stk, BT_OCTET16 stk);
UINT8 btm_proc_smp_cback(tSMP_EVT event, BD_ADDR bd_addr, tSMP_EVT_DATA *p_data);
tBTM_STATUS btm_ble_set_encryption (BD_ADDR bd_addr, void *p_ref_data, UINT8 link_role);
void btm_ble_ltk_request(UINT16 handle, UINT8 rand[8], UINT16 ediv);
tBTM_STATUS btm_ble_start_encrypt(BD_ADDR bda, BOOLEAN use_stk, BT_OCTET16 stk);
void btm_ble_link_encrypted(BD_ADDR bd_addr, UINT8 encr_enable);
#endif
/* LE device management functions */
void btm_ble_reset_id( void );
/* security related functions */
void btm_ble_increment_sign_ctr(BD_ADDR bd_addr, BOOLEAN is_local );
BOOLEAN btm_get_local_div (BD_ADDR bd_addr, UINT16 *p_div);
BOOLEAN btm_ble_get_enc_key_type(BD_ADDR bd_addr, UINT8 *p_key_types);
void btm_ble_test_command_complete(UINT8 *p);
void btm_ble_rand_enc_complete (UINT8 *p, UINT16 op_code, tBTM_RAND_ENC_CB *p_enc_cplt_cback);
void btm_sec_save_le_key(BD_ADDR bd_addr, tBTM_LE_KEY_TYPE key_type, tBTM_LE_KEY_VALUE *p_keys, BOOLEAN pass_to_application);
void btm_ble_update_sec_key_size(BD_ADDR bd_addr, UINT8 enc_key_size);
UINT8 btm_ble_read_sec_key_size(BD_ADDR bd_addr);
/* white list function */
BOOLEAN btm_update_dev_to_white_list(BOOLEAN to_add, BD_ADDR bd_addr, tBLE_ADDR_TYPE addr_type, tBTM_UPDATE_WHITELIST_CBACK *update_wl_cb);
void btm_update_scanner_filter_policy(tBTM_BLE_SFP scan_policy);
void btm_update_adv_filter_policy(tBTM_BLE_AFP adv_policy);
void btm_ble_clear_white_list (tBTM_UPDATE_WHITELIST_CBACK *update_wl_cb);
void btm_read_white_list_size_complete(UINT8 *p, UINT16 evt_len);
void btm_ble_add_2_white_list_complete(UINT8 status);
void btm_ble_remove_from_white_list_complete(UINT8 *p, UINT16 evt_len);
void btm_ble_clear_white_list_complete(UINT8 *p, UINT16 evt_len);
void btm_ble_white_list_init(UINT8 white_list_size);
/* background connection function */
BOOLEAN btm_ble_suspend_bg_conn(void);
BOOLEAN btm_ble_resume_bg_conn(void);
void btm_ble_initiate_select_conn(BD_ADDR bda);
BOOLEAN btm_ble_start_auto_conn(BOOLEAN start);
BOOLEAN btm_ble_start_select_conn(BOOLEAN start, tBTM_BLE_SEL_CBACK *p_select_cback);
BOOLEAN btm_ble_renew_bg_conn_params(BOOLEAN add, BD_ADDR bd_addr);
void btm_write_dir_conn_wl(BD_ADDR target_addr);
BOOLEAN btm_ble_update_mode_operation(UINT8 link_role, BD_ADDR bda, UINT8 status);
BOOLEAN btm_execute_wl_dev_operation(void);
void btm_ble_update_link_topology_mask(UINT8 role, BOOLEAN increase);
/* direct connection utility */
BOOLEAN btm_send_pending_direct_conn(void);
void btm_ble_enqueue_direct_conn_req(void *p_param);
/* BLE address management */
void btm_gen_resolvable_private_addr (void *p_cmd_cplt_cback);
void btm_gen_non_resolvable_private_addr (tBTM_BLE_ADDR_CBACK *p_cback, void *p);
void btm_ble_resolve_random_addr(BD_ADDR random_bda, tBTM_BLE_RESOLVE_CBACK *p_cback, void *p);
void btm_gen_resolve_paddr_low(tBTM_RAND_ENC *p);
/* privacy function */
#if (defined BLE_PRIVACY_SPT && BLE_PRIVACY_SPT == TRUE)
/* BLE address mapping with CS feature */
BOOLEAN btm_identity_addr_to_random_pseudo(BD_ADDR bd_addr, UINT8 *p_addr_type, BOOLEAN refresh);
BOOLEAN btm_random_pseudo_to_identity_addr(BD_ADDR random_pseudo, UINT8 *p_static_addr_type);
void btm_ble_refresh_peer_resolvable_private_addr(BD_ADDR pseudo_bda, BD_ADDR rra, UINT8 rra_type);
void btm_ble_refresh_local_resolvable_private_addr(BD_ADDR pseudo_addr, BD_ADDR local_rpa);
void btm_ble_read_resolving_list_entry_complete(UINT8 *p, UINT16 evt_len) ;
void btm_ble_set_addr_resolution_enable_complete(UINT8 *p, UINT16 evt_len) ;
void btm_ble_remove_resolving_list_entry_complete(UINT8 *p, UINT16 evt_len);
void btm_ble_add_resolving_list_entry_complete(UINT8 *p, UINT16 evt_len);
void btm_ble_clear_resolving_list_complete(UINT8 *p, UINT16 evt_len);
void btm_read_ble_resolving_list_size_complete (UINT8 *p, UINT16 evt_len);
void btm_ble_enable_resolving_list(UINT8);
BOOLEAN btm_ble_disable_resolving_list(UINT8 rl_mask, BOOLEAN to_resume);
void btm_ble_enable_resolving_list_for_platform (UINT8 rl_mask);
void btm_ble_resolving_list_init(UINT8 max_irk_list_sz);
void btm_ble_resolving_list_cleanup(void);
void btm_ble_add_default_entry_to_resolving_list(void);
#endif
void btm_ble_multi_adv_configure_rpa (tBTM_BLE_MULTI_ADV_INST *p_inst);
void btm_ble_multi_adv_init(void);
void *btm_ble_multi_adv_get_ref(UINT8 inst_id);
void btm_ble_multi_adv_cleanup(void);
void btm_ble_multi_adv_reenable(UINT8 inst_id);
void btm_ble_multi_adv_enb_privacy(BOOLEAN enable);
char btm_ble_map_adv_tx_power(int tx_power_index);
void btm_ble_batchscan_init(void);
void btm_ble_batchscan_cleanup(void);
void btm_ble_adv_filter_init(void);
void btm_ble_adv_filter_cleanup(void);
BOOLEAN btm_ble_topology_check(tBTM_BLE_STATE_MASK request);
BOOLEAN btm_ble_clear_topology_mask(tBTM_BLE_STATE_MASK request_state);
BOOLEAN btm_ble_set_topology_mask(tBTM_BLE_STATE_MASK request_state);
tBTM_BLE_STATE_MASK btm_ble_get_topology_mask(void);
#if BTM_BLE_CONFORMANCE_TESTING == TRUE
void btm_ble_set_no_disc_if_pair_fail (BOOLEAN disble_disc);
void btm_ble_set_test_mac_value (BOOLEAN enable, UINT8 *p_test_mac_val);
void btm_ble_set_test_local_sign_cntr_value(BOOLEAN enable, UINT32 test_local_sign_cntr);
void btm_set_random_address(BD_ADDR random_bda);
void btm_ble_set_keep_rfu_in_auth_req(BOOLEAN keep_rfu);
#endif
BOOLEAN btm_get_current_conn_params(BD_ADDR bda, UINT16 *interval, UINT16 *latency, UINT16 *timeout);
#if (BLE_50_FEATURE_SUPPORT == TRUE)
void btm_ble_update_phy_evt(tBTM_BLE_UPDATE_PHY *params);
void btm_ble_scan_timeout_evt(void);
void btm_ble_adv_set_terminated_evt(tBTM_BLE_ADV_TERMINAT *params);
void btm_ble_ext_adv_report_evt(tBTM_BLE_EXT_ADV_REPORT *params);
void btm_ble_scan_req_received_evt(tBTM_BLE_SCAN_REQ_RECEIVED *params);
void btm_ble_channel_select_algorithm_evt(tBTM_BLE_CHANNEL_SEL_ALG *params);
void btm_ble_periodic_adv_report_evt(tBTM_PERIOD_ADV_REPORT *params);
void btm_ble_periodic_adv_sync_lost_evt(tBTM_BLE_PERIOD_ADV_SYNC_LOST *params);
void btm_ble_periodic_adv_sync_establish_evt(tBTM_BLE_PERIOD_ADV_SYNC_ESTAB *params);
#endif // #if (BLE_50_FEATURE_SUPPORT == TRUE)
#if (BLE_FEAT_PERIODIC_ADV_SYNC_TRANSFER == TRUE)
void btm_ble_periodic_adv_sync_trans_recv_evt(tBTM_BLE_PERIOD_ADV_SYNC_TRANS_RECV *params);
#endif // #if (BLE_FEAT_PERIODIC_ADV_SYNC_TRANSFER == TRUE)
/*
#ifdef __cplusplus
}
#endif
*/
#endif
File diff suppressed because it is too large Load Diff