Beispiel #1
0
/*******************************************************************************
**
** 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_update_bg_conn_list
**
** Description      This function update the local background connection device list.
*******************************************************************************/
BOOLEAN btm_update_bg_conn_list(BOOLEAN to_add, BD_ADDR bd_addr)
{
    tBTM_BLE_CB             *p_cb = &btm_cb.ble_ctr_cb;
    tBTM_LE_BG_CONN_DEV     *p_bg_dev = &p_cb->bg_dev_list[0], *p_next, *p_cur;
    UINT8                   i, j;
    BOOLEAN             ret = FALSE;

    BTM_TRACE_EVENT ("btm_update_bg_conn_list");

    if ((to_add && (p_cb->bg_dev_num == BTM_BLE_MAX_BG_CONN_DEV_NUM || p_cb->num_empty_filter == 0)))
    {
        BTM_TRACE_DEBUG("num_empty_filter = %d", p_cb->num_empty_filter);
        return ret;
    }

    for (i = 0; i < BTM_BLE_MAX_BG_CONN_DEV_NUM; i ++, p_bg_dev ++)
    {
        if (p_bg_dev->in_use && memcmp(p_bg_dev->bd_addr, bd_addr, BD_ADDR_LEN) == 0)
        {
            if (!to_add)
            {
                memset(p_bg_dev, 0, sizeof(tBTM_LE_BG_CONN_DEV));
                p_cb->bg_dev_num --;
                p_cur = p_bg_dev;
                p_next = p_bg_dev + 1;
                for (j = i + 1; j < BTM_BLE_MAX_BG_CONN_DEV_NUM && p_next->in_use;
                     j ++, p_cur ++, p_next ++)
                {
                    memcpy(p_cur, p_next, sizeof(tBTM_LE_BG_CONN_DEV));
                    memset(p_next, 0, sizeof(tBTM_LE_BG_CONN_DEV));
                }
            }
            ret = TRUE;
            break;
        }
        else if (!p_bg_dev->in_use && to_add)
        {
            BTM_TRACE_DEBUG("add new WL entry in bg_dev_list");

            memcpy(p_bg_dev->bd_addr, bd_addr, BD_ADDR_LEN);
            p_bg_dev->in_use = TRUE;
            p_cb->bg_dev_num ++;

            ret = TRUE;
            break;
        }
    }


    return ret;
}
/*******************************************************************************
**
** 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 */
        btsnd_hcic_ble_set_random_addr(p_cb->private_addr);

        p_cb->own_addr_type = BLE_ADDR_RANDOM;

        /* 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");
    }
}
/*******************************************************************************
**
** 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);
    }
}
Beispiel #5
0
/*******************************************************************************
**
** 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(UINT16 rec_index)
{
    /* 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 rec_index = %d", __func__, rec_index);

    if (rec_index < BTM_SEC_MAX_DEVICE_RECORDS) {
        tSMP_ENC output;
        tBTM_SEC_DEV_REC *p_dev_rec;
        p_dev_rec = &btm_cb.sec_dev_rec[rec_index];

        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;
        }
    } else { /* no  match found */
        btm_ble_resolve_address_cmpl();
        return TRUE;
    }
}
Beispiel #6
0
/*******************************************************************************
**
** 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;
}
/*******************************************************************************
**
** 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         smp_process_confirm
**
** Description      This function is called when SConfirm/MConfirm is generated
**                  proceed to send the Confirm request/response to peer device.
**
** Returns          void
**
*******************************************************************************/
static void smp_process_confirm(tSMP_CB *p_cb, tSMP_ENC *p)
{
    tSMP_KEY    key;

    SMP_TRACE_DEBUG ("smp_process_confirm ");
#if SMP_CONFORMANCE_TESTING == TRUE
    if (p_cb->enable_test_confirm_val)
    {
        BTM_TRACE_DEBUG ("Use confirm value from script");
        memcpy(p_cb->confirm, p_cb->test_confirm, BT_OCTET16_LEN);
    }
    else
        memcpy(p_cb->confirm, p->param_buf, BT_OCTET16_LEN);
#else
    memcpy(p_cb->confirm, p->param_buf, BT_OCTET16_LEN);
#endif


#if (SMP_DEBUG == TRUE)
    SMP_TRACE_DEBUG("Confirm  Generated");
    smp_debug_print_nbyte_little_endian ((UINT8 *)p_cb->confirm,  (const UINT8 *)"Confirm", 16);
#endif

    key.key_type = SMP_KEY_TYPE_CFM;
    key.p_data = p->param_buf;

    smp_sm_event(p_cb, SMP_KEY_READY_EVT, &key);
}
Beispiel #9
0
/*******************************************************************************
**
** Function         btm_vendor_specific_evt
**
** Description      Process event HCI_VENDOR_SPECIFIC_EVT
**
**                  Note: Some controllers do not send command complete, so
**                  the callback and busy flag are cleared here also.
**
** Returns          void
**
*******************************************************************************/
void btm_vendor_specific_evt (UINT8 *p, UINT8 evt_len)
{
    UINT8 i;

    BTM_TRACE_DEBUG ("BTM Event: Vendor Specific event from controller");

    for (i=0; i<BTM_MAX_VSE_CALLBACKS; i++)
    {
        if (btm_cb.devcb.p_vend_spec_cb[i])
            (*btm_cb.devcb.p_vend_spec_cb[i])(evt_len, p);
    }
}
/*******************************************************************************
**
** 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_advfilt_enq_op_q
**
** Description      enqueue an adv filter operation in q to check command complete
**                  status
**
** Returns          void
**
*******************************************************************************/
void btm_ble_advfilt_enq_op_q(UINT8 action, UINT8 ocf, tBTM_BLE_FILT_CB_EVT cb_evt,
                              tBTM_BLE_REF_VALUE ref, tBTM_BLE_PF_CFG_CBACK *p_cmpl_cback,
                              tBTM_BLE_PF_PARAM_CBACK  *p_filt_param_cback)
{
    btm_ble_adv_filt_cb.op_q.action_ocf[btm_ble_adv_filt_cb.op_q.next_idx] = (action |(ocf << 4));
    btm_ble_adv_filt_cb.op_q.ref_value[btm_ble_adv_filt_cb.op_q.next_idx] = ref;
    btm_ble_adv_filt_cb.op_q.cb_evt[btm_ble_adv_filt_cb.op_q.next_idx] = cb_evt;
    btm_ble_adv_filt_cb.op_q.p_scan_cfg_cback[btm_ble_adv_filt_cb.op_q.next_idx] = p_cmpl_cback;
    btm_ble_adv_filt_cb.op_q.p_filt_param_cback[btm_ble_adv_filt_cb.op_q.next_idx]
        = p_filt_param_cback;
    BTM_TRACE_DEBUG("btm_ble_advfilt_enq_op_q: act_ocf:%d, action:%d, ocf:%d,cb_evt;%d, cback:%x",
        btm_ble_adv_filt_cb.op_q.action_ocf[btm_ble_adv_filt_cb.op_q.next_idx], action,
        ocf, cb_evt, p_cmpl_cback);
    btm_ble_adv_filt_cb.op_q.next_idx = (btm_ble_adv_filt_cb.op_q.next_idx + 1)
                    % BTM_BLE_PF_TYPE_MAX;
}
/*******************************************************************************
**
** Function         btm_ble_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 = GKI_getbuf(len + data_len);
            memcpy(p_app_data, p_orig_data, len);
            memcpy(p_app_data+len, p_data, data_len);
            GKI_freebuf(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 = GKI_getbuf(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;
        }
    }
}
Beispiel #14
0
/*******************************************************************************
**
** Function         btm_decode_ext_features_page
**
** Description      This function is decodes a features page.
**
** Returns          void
**
*******************************************************************************/
static void btm_decode_ext_features_page (UINT8 page_number, const UINT8 *p_features)
{
    BTM_TRACE_DEBUG ("btm_decode_ext_features_page page: %d", page_number);
    switch (page_number)
    {
    /* Extended (Legacy) Page 0 */
    case HCI_EXT_FEATURES_PAGE_0:

        /* Create ACL supported packet types mask */
        btm_cb.btm_acl_pkt_types_supported = (BTM_ACL_PKT_TYPES_MASK_DH1 +
                                              BTM_ACL_PKT_TYPES_MASK_DM1);

        if (HCI_3_SLOT_PACKETS_SUPPORTED(p_features))
            btm_cb.btm_acl_pkt_types_supported |= (BTM_ACL_PKT_TYPES_MASK_DH3 +
                                                   BTM_ACL_PKT_TYPES_MASK_DM3);

        if (HCI_5_SLOT_PACKETS_SUPPORTED(p_features))
            btm_cb.btm_acl_pkt_types_supported |= (BTM_ACL_PKT_TYPES_MASK_DH5 +
                                                   BTM_ACL_PKT_TYPES_MASK_DM5);

        /* Add in EDR related ACL types */
        if (!HCI_EDR_ACL_2MPS_SUPPORTED(p_features))
        {
            btm_cb.btm_acl_pkt_types_supported |= (BTM_ACL_PKT_TYPES_MASK_NO_2_DH1 +
                                                   BTM_ACL_PKT_TYPES_MASK_NO_2_DH3 +
                                                   BTM_ACL_PKT_TYPES_MASK_NO_2_DH5);
        }

        if (!HCI_EDR_ACL_3MPS_SUPPORTED(p_features))
        {
            btm_cb.btm_acl_pkt_types_supported |= (BTM_ACL_PKT_TYPES_MASK_NO_3_DH1 +
                                                   BTM_ACL_PKT_TYPES_MASK_NO_3_DH3 +
                                                   BTM_ACL_PKT_TYPES_MASK_NO_3_DH5);
        }

        /* Check to see if 3 and 5 slot packets are available */
        if (HCI_EDR_ACL_2MPS_SUPPORTED(p_features) ||
            HCI_EDR_ACL_3MPS_SUPPORTED(p_features))
        {
            if (!HCI_3_SLOT_EDR_ACL_SUPPORTED(p_features))
                btm_cb.btm_acl_pkt_types_supported |= (BTM_ACL_PKT_TYPES_MASK_NO_2_DH3 +
                                                       BTM_ACL_PKT_TYPES_MASK_NO_3_DH3);

            if (!HCI_5_SLOT_EDR_ACL_SUPPORTED(p_features))
                btm_cb.btm_acl_pkt_types_supported |= (BTM_ACL_PKT_TYPES_MASK_NO_2_DH5 +
                                                       BTM_ACL_PKT_TYPES_MASK_NO_3_DH5);
        }

        BTM_TRACE_DEBUG("Local supported ACL packet types: 0x%04x",
                         btm_cb.btm_acl_pkt_types_supported);

        /* Create (e)SCO supported packet types mask */
        btm_cb.btm_sco_pkt_types_supported = 0;
#if BTM_SCO_INCLUDED == TRUE
        btm_cb.sco_cb.esco_supported = FALSE;
#endif
        if (HCI_SCO_LINK_SUPPORTED(p_features))
        {
            btm_cb.btm_sco_pkt_types_supported = BTM_SCO_PKT_TYPES_MASK_HV1;

            if (HCI_HV2_PACKETS_SUPPORTED(p_features))
                btm_cb.btm_sco_pkt_types_supported |= BTM_SCO_PKT_TYPES_MASK_HV2;

            if (HCI_HV3_PACKETS_SUPPORTED(p_features))
                btm_cb.btm_sco_pkt_types_supported |= BTM_SCO_PKT_TYPES_MASK_HV3;
        }

        if (HCI_ESCO_EV3_SUPPORTED(p_features))
            btm_cb.btm_sco_pkt_types_supported |= BTM_SCO_PKT_TYPES_MASK_EV3;

        if (HCI_ESCO_EV4_SUPPORTED(p_features))
            btm_cb.btm_sco_pkt_types_supported |= BTM_SCO_PKT_TYPES_MASK_EV4;

        if (HCI_ESCO_EV5_SUPPORTED(p_features))
            btm_cb.btm_sco_pkt_types_supported |= BTM_SCO_PKT_TYPES_MASK_EV5;
#if BTM_SCO_INCLUDED == TRUE
        if (btm_cb.btm_sco_pkt_types_supported & BTM_ESCO_LINK_ONLY_MASK)
        {
            btm_cb.sco_cb.esco_supported = TRUE;

            /* Add in EDR related eSCO types */
            if (HCI_EDR_ESCO_2MPS_SUPPORTED(p_features))
            {
                if (!HCI_3_SLOT_EDR_ESCO_SUPPORTED(p_features))
                    btm_cb.btm_sco_pkt_types_supported |= BTM_SCO_PKT_TYPES_MASK_NO_2_EV5;
            }
            else
            {
                btm_cb.btm_sco_pkt_types_supported |= (BTM_SCO_PKT_TYPES_MASK_NO_2_EV3 +
                                                       BTM_SCO_PKT_TYPES_MASK_NO_2_EV5);
            }

            if (HCI_EDR_ESCO_3MPS_SUPPORTED(p_features))
            {
                if (!HCI_3_SLOT_EDR_ESCO_SUPPORTED(p_features))
                    btm_cb.btm_sco_pkt_types_supported |= BTM_SCO_PKT_TYPES_MASK_NO_3_EV5;
            }
            else
            {
                btm_cb.btm_sco_pkt_types_supported |= (BTM_SCO_PKT_TYPES_MASK_NO_3_EV3 +
                                                       BTM_SCO_PKT_TYPES_MASK_NO_3_EV5);
            }
        }
#endif

        BTM_TRACE_DEBUG("Local supported SCO packet types: 0x%04x",
                         btm_cb.btm_sco_pkt_types_supported);

        /* Create Default Policy Settings */
        if (HCI_SWITCH_SUPPORTED(p_features))
            btm_cb.btm_def_link_policy |= HCI_ENABLE_MASTER_SLAVE_SWITCH;
        else
            btm_cb.btm_def_link_policy &= ~HCI_ENABLE_MASTER_SLAVE_SWITCH;

        if (HCI_HOLD_MODE_SUPPORTED(p_features))
            btm_cb.btm_def_link_policy |= HCI_ENABLE_HOLD_MODE;
        else
            btm_cb.btm_def_link_policy &= ~HCI_ENABLE_HOLD_MODE;

        if (HCI_SNIFF_MODE_SUPPORTED(p_features))
            btm_cb.btm_def_link_policy |= HCI_ENABLE_SNIFF_MODE;
        else
            btm_cb.btm_def_link_policy &= ~HCI_ENABLE_SNIFF_MODE;

        if (HCI_PARK_MODE_SUPPORTED(p_features))
            btm_cb.btm_def_link_policy |= HCI_ENABLE_PARK_MODE;
        else
            btm_cb.btm_def_link_policy &= ~HCI_ENABLE_PARK_MODE;

        btm_sec_dev_reset ();

        if (HCI_LMP_INQ_RSSI_SUPPORTED(p_features))
        {
            if (HCI_EXT_INQ_RSP_SUPPORTED(p_features))
                BTM_SetInquiryMode (BTM_INQ_RESULT_EXTENDED);
            else
                BTM_SetInquiryMode (BTM_INQ_RESULT_WITH_RSSI);
        }

#if L2CAP_NON_FLUSHABLE_PB_INCLUDED == TRUE
        if( HCI_NON_FLUSHABLE_PB_SUPPORTED(p_features))
            l2cu_set_non_flushable_pbf(TRUE);
        else
            l2cu_set_non_flushable_pbf(FALSE);
#endif
        BTM_SetPageScanType (BTM_DEFAULT_SCAN_TYPE);
        BTM_SetInquiryScanType (BTM_DEFAULT_SCAN_TYPE);

        break;

    /* Extended Page 1 */
    case HCI_EXT_FEATURES_PAGE_1:
        /* Nothing to do for page 1 */
        break;

    /* Extended Page 2 */
    case HCI_EXT_FEATURES_PAGE_2:
        /* Nothing to do for page 2 */
        break;

    default:
        BTM_TRACE_ERROR("btm_decode_ext_features_page page=%d unknown", page_number);
        break;
    }
}
/*******************************************************************************
**
** 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)
            {
                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_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;
}