예제 #1
0
/*******************************************************************************
**
** Function         SMP_ConfirmReply
**
** Description      This function is called after Security Manager submitted
**                  numeric comparison request to the application.
**
** Parameters:      bd_addr      - Address of the device with which numeric
**                                 comparison was requested
**                  res          - comparison result SMP_SUCCESS if success
**
*******************************************************************************/
void SMP_ConfirmReply (BD_ADDR bd_addr, UINT8 res)
{
    tSMP_CB *p_cb = & smp_cb;
    UINT8   failure = SMP_NUMERIC_COMPAR_FAIL;

    SMP_TRACE_EVENT ("%s: Result:%d", __FUNCTION__, res);

    /* If timeout already expired or has been canceled, ignore the reply */
    if (p_cb->cb_evt != SMP_NC_REQ_EVT) {
        SMP_TRACE_WARNING ("%s() - Wrong State: %d", __FUNCTION__, p_cb->state);
        return;
    }

    if (memcmp (bd_addr, p_cb->pairing_bda, BD_ADDR_LEN) != 0) {
        SMP_TRACE_ERROR ("%s() - Wrong BD Addr", __FUNCTION__);
        return;
    }

    if (btm_find_dev (bd_addr) == NULL) {
        SMP_TRACE_ERROR ("%s() - no dev CB", __FUNCTION__);
        return;
    }

    if (res != SMP_SUCCESS) {
        SMP_TRACE_WARNING ("%s() - Numeric Comparison fails", __FUNCTION__);
        /* send pairing failure */
        smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &failure);
    } else {
        smp_sm_event(p_cb, SMP_SC_NC_OK_EVT, NULL);
    }
}
예제 #2
0
/*******************************************************************************
**
** Function         SMP_KeypressNotification
**
** Description      This function is called to notify Security Manager about Keypress Notification.
**
** Parameters:     bd_addr      Address of the device to send keypress notification to
**                 value        Keypress notification parameter value
**
*******************************************************************************/
void SMP_KeypressNotification (BD_ADDR bd_addr, UINT8 value)
{
    tSMP_CB   *p_cb = &smp_cb;

    SMP_TRACE_EVENT ("%s: Value: %d", __FUNCTION__, value);

    if (memcmp (bd_addr, p_cb->pairing_bda, BD_ADDR_LEN) != 0) {
        SMP_TRACE_ERROR ("%s() - Wrong BD Addr", __FUNCTION__);
        return;
    }

    if (btm_find_dev (bd_addr) == NULL) {
        SMP_TRACE_ERROR ("%s() - no dev CB", __FUNCTION__);
        return;
    }

    /* Keypress Notification is used by a device with KeyboardOnly IO capabilities */
    /* during the passkey entry protocol */
    if (p_cb->local_io_capability != SMP_IO_CAP_IN) {
        SMP_TRACE_ERROR ("%s() - wrong local IO capabilities %d",
                         __FUNCTION__, p_cb->local_io_capability);
        return;
    }

    if (p_cb->selected_association_model != SMP_MODEL_SEC_CONN_PASSKEY_ENT) {
        SMP_TRACE_ERROR ("%s() - wrong protocol %d", __FUNCTION__,
                         p_cb->selected_association_model);
        return;
    }

    smp_sm_event(p_cb, SMP_KEYPRESS_NOTIFICATION_EVENT, &value);
}
예제 #3
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_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)
{
    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);
            }
            else
            {
#if (defined BLE_PRIVACY_SPT && BLE_PRIVACY_SPT == TRUE)
                /* add device into IRK list */
                btm_ble_vendor_irk_list_load_dev(p_dev_rec);
#endif
            }
            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);
            }
        }
        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);
            }
        }
    }    /* 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;

}
/*******************************************************************************
**
** 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_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_EVENT0 ("btm_find_or_alloc_dev");
    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);
}
예제 #7
0
/*******************************************************************************
**
** 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)
{
    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);

        started = btsnd_hcic_ble_remove_from_white_list (addr_type, bd_addr);
        if (to_add)
            started = btsnd_hcic_ble_add_white_list (addr_type, bd_addr);
    }

    return started;

}
/*******************************************************************************
**
** Function         btm_ble_map_bda_to_conn_bda
**
** Description      This function map a BD address to the real connection address
**                  and return the connection address type.
*******************************************************************************/
tBLE_ADDR_TYPE btm_ble_map_bda_to_conn_bda(BD_ADDR bd_addr)
{
    tBTM_SEC_DEV_REC    *p_dev_rec = NULL;
    BTM_TRACE_EVENT ("btm_ble_map_bda_to_conn_bda");
    if ((p_dev_rec = btm_find_dev (bd_addr)) != NULL &&
        p_dev_rec->device_type == BT_DEVICE_TYPE_BLE)
    {
        if (p_dev_rec->ble.ble_addr_type != BLE_ADDR_PUBLIC)
        {
            memcpy(bd_addr, p_dev_rec->ble.static_addr, BD_ADDR_LEN);
        }
        return p_dev_rec->ble.ble_addr_type;
    }
    else
        return BLE_ADDR_PUBLIC;
}
예제 #9
0
/*******************************************************************************
**
** 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_static_addr_type |= BLE_ADDR_TYPE_ID_BIT;
            }
            return TRUE;
        }
    }
#endif
    return FALSE;
}
예제 #10
0
/*******************************************************************************
**
** Function         SMP_PasskeyReply
**
** Description      This function is called after Security Manager submitted
**                  passkey request to the application.
**
** Parameters:      bd_addr      - Address of the device for which passkey was requested
**                  res          - result of the operation SMP_SUCCESS if success
**                  passkey - numeric value in the range of
**                  BTM_MIN_PASSKEY_VAL(0) - BTM_MAX_PASSKEY_VAL(999999(0xF423F)).
**
*******************************************************************************/
void SMP_PasskeyReply (BD_ADDR bd_addr, UINT8 res, UINT32 passkey)
{
    tSMP_CB *p_cb = & smp_cb;
    UINT8   failure = SMP_PASSKEY_ENTRY_FAIL;
    tBTM_SEC_DEV_REC *p_dev_rec;

    SMP_TRACE_EVENT2 ("SMP_PasskeyReply: Key: %d  Result:%d",
                      passkey, res);

    /* If timeout already expired or has been canceled, ignore the reply */
    if (p_cb->cb_evt != SMP_PASSKEY_REQ_EVT)
    {
        SMP_TRACE_WARNING1 ("SMP_PasskeyReply() - Wrong State: %d", p_cb->state);
        return;
    }

    if (memcmp (bd_addr, p_cb->pairing_bda, BD_ADDR_LEN) != 0)
    {
        SMP_TRACE_ERROR0 ("SMP_PasskeyReply() - Wrong BD Addr");
        return;
    }

    if ((p_dev_rec = btm_find_dev (bd_addr)) == NULL)
    {
        SMP_TRACE_ERROR0 ("SMP_PasskeyReply() - no dev CB");
        return;
    }


    if (passkey > BTM_MAX_PASSKEY_VAL || res != SMP_SUCCESS)
    {
        SMP_TRACE_WARNING1 ("SMP_PasskeyReply() - Wrong key len: %d or passkey entry fail", passkey);
        /* send pairing failure */
        smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &failure);

    }
    else
    {
        smp_convert_string_to_tk(p_cb->tk, passkey);
    }

    return;
}
/*******************************************************************************
**
** Function         btm_random_pseudo_to_public
**
** Description      This function map a random pseudo address to a public address
**                  random_pseudo is input and output parameter
**
*******************************************************************************/
BOOLEAN btm_random_pseudo_to_public(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.ble_addr_type == BLE_ADDR_RANDOM &&
            BTM_BLE_IS_RESOLVE_BDA(p_dev_rec->bd_addr) &&
            (p_dev_rec->ble.key_type & BTM_LE_KEY_PID) != 0)
        {
            BTM_TRACE_EVENT ("btm_random_pseudo_to_public found the puclic static address!");
            * p_static_addr_type = p_dev_rec->ble.static_addr_type;
            memcpy(random_pseudo, p_dev_rec->ble.static_addr, BD_ADDR_LEN);
            return TRUE;
        }
    }
#endif
    return FALSE;
}
/*******************************************************************************
**
** Function         BTM_SecDeleteDevice
**
** Description      Free resources associated with the device.
**
** Parameters:      bd_addr          - BD address of the peer
**
** Returns          TRUE if removed OK, FALSE if not found or ACL link is active
**
*******************************************************************************/
BOOLEAN BTM_SecDeleteDevice (BD_ADDR bd_addr)
{
    tBTM_SEC_DEV_REC  *p_dev_rec;

    if (BTM_IsAclConnectionUp(bd_addr))
    {
        BTM_TRACE_WARNING0("BTM_SecDeleteDevice FAILED: Cannot Delete when connection is active");
        return(FALSE);
    }

    if ((p_dev_rec = btm_find_dev (bd_addr)) == NULL)
        return(FALSE);

    btm_sec_free_dev (p_dev_rec);

    /* Tell controller to get rid of the link key if it has one stored */
    BTM_DeleteStoredLinkKey (bd_addr, NULL);

    return(TRUE);
}
/*******************************************************************************
**
** 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 && HCI_SWITCH_SUPPORTED(btm_cb.devcb.local_lmp_features[HCI_EXT_FEATURES_PAGE_0]))
    {
        if (HCI_SWITCH_SUPPORTED(p_dev_rec->features[HCI_EXT_FEATURES_PAGE_0]))
        {
            BTM_TRACE_DEBUG0("btm_dev_support_switch return TRUE (feature found)");
            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_DEBUG0("btm_dev_support_switch return TRUE (feature empty)");
            return (TRUE);
        }
    }

    BTM_TRACE_DEBUG0("btm_dev_support_switch return FALSE");
    return(FALSE);
}
예제 #14
0
/*******************************************************************************
**
** Function         btm_update_dev_to_white_list
**
** Description      This function adds a device into white list.
*******************************************************************************/
BOOLEAN btm_update_dev_to_white_list(BOOLEAN to_add, BD_ADDR bd_addr, tBLE_ADDR_TYPE addr_type)
{
    /* look up the sec device record, and find the address */
    tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb;
    tBTM_SEC_DEV_REC    *p_dev_rec;
    BD_ADDR             dummy_bda = {0};
    BOOLEAN             started = FALSE, suspend = FALSE;

    if (btm_cb.btm_inq_vars.inq_active)
    {
        suspend = TRUE;
        btsnd_hcic_ble_set_scan_enable (BTM_BLE_SCAN_DISABLE, BTM_BLE_DUPLICATE_ENABLE);
    }

    if ((p_dev_rec = btm_find_dev (bd_addr)) != NULL &&
        p_dev_rec->device_type == BT_DEVICE_TYPE_BLE)
    {
        BTM_TRACE_DEBUG0("btm_update_dev_to_white_list 1");

        if ((to_add && p_cb->num_empty_filter == 0) ||
            (!to_add && p_cb->num_empty_filter == p_cb->max_filter_entries))
        {
            BTM_TRACE_ERROR1("num_entry available in controller: %d", p_cb->num_empty_filter);
            return started;
        }


        if ( p_dev_rec->ble.ble_addr_type == BLE_ADDR_PUBLIC)
        {
            if (to_add)
                started = btsnd_hcic_ble_add_white_list (BLE_ADDR_PUBLIC, bd_addr);
            else
                started = btsnd_hcic_ble_remove_from_white_list (BLE_ADDR_PUBLIC, bd_addr);
        }
        else
        {
            if (BLE_ADDR_IS_STATIC(bd_addr))
            {
                if (to_add)
                    started = btsnd_hcic_ble_add_white_list (BLE_ADDR_RANDOM, bd_addr);
                else
                    started = btsnd_hcic_ble_remove_from_white_list (BLE_ADDR_RANDOM, bd_addr);

            }
            if (memcmp(p_dev_rec->ble.reconn_addr, dummy_bda, BD_ADDR_LEN) != 0)
            {
                if (to_add)
                    started = btsnd_hcic_ble_add_white_list (BLE_ADDR_RANDOM, p_dev_rec->ble.reconn_addr);
                else
                    started = btsnd_hcic_ble_remove_from_white_list (BLE_ADDR_RANDOM, p_dev_rec->ble.reconn_addr);
            }
        }
    }
    /* if not a known device, shall we add it? */
    else
    {
        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);
    }

    if (suspend)
    {
        btsnd_hcic_ble_set_scan_enable (BTM_BLE_SCAN_ENABLE, BTM_BLE_DUPLICATE_DISABLE);
    }

    return started;
}
/*******************************************************************************
**
** 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.
**                  pin_len          - length of pin key
**
** 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_len)
{
    tBTM_SEC_DEV_REC  *p_dev_rec;
    int               i, j;
    BOOLEAN           found = FALSE;

    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. */
        for (i = 0; i < BTM_SEC_MAX_DEVICE_RECORDS; i++)
        {
            if (!(btm_cb.sec_dev_rec[i].sec_flags & BTM_SEC_IN_USE))
            {
                p_dev_rec = &btm_cb.sec_dev_rec[i];

                /* 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);

#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
                break;
            }
        }

        if (!p_dev_rec)
            return(FALSE);
    }

    p_dev_rec->timestamp = btm_cb.dev_rec_count++;

    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, sizeof (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_EVENT6 ("BTM_SecAddDevice()  BDA: %02x:%02x:%02x:%02x:%02x:%02x",
                          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_key_len = pin_len;

#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;

    return(TRUE);
}