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