前面讲到btm_sec_bond_by_transport 这个接口,继续---->
/*******************************************************************************
*
* Function btm_sec_bond_by_transport
*
* Description this is the bond function that will start either SSP or SMP.
*
* Parameters: bd_addr - Address of the device to bond
* pin_len - length in bytes of the PIN Code
* p_pin - pointer to array with the PIN Code
* trusted_mask - bitwise OR of trusted services
* (array of uint32_t)
*
* Note: After 2.1 parameters are not used and preserved here not to change API
******************************************************************************/
tBTM_STATUS btm_sec_bond_by_transport(const RawAddress& bd_addr,
tBT_TRANSPORT transport, uint8_t pin_len,
uint8_t* p_pin, uint32_t trusted_mask[]) {
........
# 判断controller是否ready !
if (!controller_get_interface()->get_is_ready()) {
BTM_TRACE_ERROR("%s controller module is not ready", __func__);
return (BTM_NO_RESOURCES);
}
BTM_TRACE_DEBUG("before update sec_flags=0x%x", p_dev_rec->sec_flags);
# 已配对返回 !
/* Finished if connection is active and already paired */
if (((p_dev_rec->hci_handle != BTM_SEC_INVALID_HANDLE) &&
transport == BT_TRANSPORT_BR_EDR &&
(p_dev_rec->sec_flags & BTM_SEC_AUTHENTICATED)) ||
((p_dev_rec->ble_hci_handle != BTM_SEC_INVALID_HANDLE) &&
transport == BT_TRANSPORT_LE &&
(p_dev_rec->sec_flags & BTM_SEC_LE_AUTHENTICATED))) {
BTM_TRACE_WARNING("BTM_SecBond -> Already Paired");
return (BTM_SUCCESS);
}
# 向Controller发送HCIC_PARAM_SIZE_DELETE_STORED_KEY 删除link key !
/* Tell controller to get rid of the link key if it has one stored */
if ((BTM_DeleteStoredLinkKey(&bd_addr, NULL)) != BTM_SUCCESS)
return (BTM_NO_RESOURCES);
/* Save the PIN code if we got a valid one */
if (p_pin && (pin_len <= PIN_CODE_LEN) && (pin_len != 0)) {
btm_cb.pin_code_len = pin_len;
p_dev_rec->pin_code_length = pin_len;
memcpy(btm_cb.pin_code, p_pin, PIN_CODE_LEN);
}
btm_cb.pairing_bda = bd_addr;
btm_cb.pairing_flags = BTM_PAIR_FLAGS_WE_STARTED_DD;
p_dev_rec->security_required = BTM_SEC_OUT_AUTHENTICATE;
p_dev_rec->is_originator = true;
if (trusted_mask)
BTM_SEC_COPY_TRUSTED_DEVICE(trusted_mask, p_dev_rec->trusted_mask);
if (transport == BT_TRANSPORT_LE) {
btm_ble_init_pseudo_addr(p_dev_rec, bd_addr);
p_dev_rec->sec_flags &= ~BTM_SEC_LE_MASK;
if (SMP_Pair(bd_addr) == SMP_STARTED) {
btm_cb.pairing_flags |= BTM_PAIR_FLAGS_LE_ACTIVE;
p_dev_rec->sec_state = BTM_SEC_STATE_AUTHENTICATING;
btm_sec_change_pairing_state(BTM_PAIR_STATE_WAIT_AUTH_COMPLETE);
return BTM_CMD_STARTED;
}
btm_cb.pairing_flags = 0;
return (BTM_NO_RESOURCES);
}
p_dev_rec->sec_flags &=
~(BTM_SEC_LINK_KEY_KNOWN | BTM_SEC_AUTHENTICATED | BTM_SEC_ENCRYPTED |
BTM_SEC_ROLE_SWITCHED | BTM_SEC_LINK_KEY_AUTHED);
# 判断是否支持简单安全配对SSP,以及对应的逻辑
BTM_TRACE_DEBUG("after update sec_flags=0x%x", p_dev_rec->sec_flags);
if (!controller_get_interface()->supports_simple_pairing()) {
/* The special case when we authenticate keyboard. Set pin type to fixed */
/* It would be probably better to do it from the application, but it is */
/* complicated */
if (((p_dev_rec->dev_class[1] & BTM_COD_MAJOR_CLASS_MASK) ==
BTM_COD_MAJOR_PERIPHERAL) &&
(p_dev_rec->dev_class[2] & BTM_COD_MINOR_KEYBOARD) &&
(btm_cb.cfg.pin_type != HCI_PIN_TYPE_FIXED)) {
btm_cb.pin_type_changed = true;
btsnd_hcic_write_pin_type(HCI_PIN_TYPE_FIXED);
}
}
.......
/* If connection already exists... */
if (p && p->hci_handle != BTM_SEC_INVALID_HANDLE) {
btm_sec_start_authentication(p_dev_rec);
btm_sec_change_pairing_state(BTM_PAIR_STATE_WAIT_PIN_REQ);
/* Mark lcb as bonding */
l2cu_update_lcb_4_bonding(bd_addr, true);
return (BTM_CMD_STARTED);
}
BTM_TRACE_DEBUG("sec mode: %d sm4:x%x", btm_cb.security_mode, p_dev_rec->sm4);
if (!controller_get_interface()->supports_simple_pairing() ||
(p_dev_rec->sm4 == BTM_SM4_KNOWN)) {
if (btm_sec_check_prefetch_pin(p_dev_rec)) return (BTM_CMD_STARTED);
}
if ((btm_cb.security_mode == BTM_SEC_MODE_SP ||
btm_cb.security_mode == BTM_SEC_MODE_SP_DEBUG ||
btm_cb.security_mode == BTM_SEC_MODE_SC) &&
BTM_SEC_IS_SM4_UNKNOWN(p_dev_rec->sm4)) {
/* local is 2.1 and peer is unknown */
if ((p_dev_rec->sm4 & BTM_SM4_CONN_PEND) == 0) {
/* we are not accepting connection request from peer
* -> RNR (to learn if peer is 2.1)
* RNR when no ACL causes HCI_RMT_HOST_SUP_FEAT_NOTIFY_EVT */
btm_sec_change_pairing_state(BTM_PAIR_STATE_GET_REM_NAME);
status = BTM_ReadRemoteDeviceName(bd_addr, NULL, BT_TRANSPORT_BR_EDR);
} else {
/* We are accepting connection request from peer */
btm_sec_change_pairing_state(BTM_PAIR_STATE_WAIT_PIN_REQ);
status = BTM_CMD_STARTED;
}
BTM_TRACE_DEBUG("State:%s sm4: 0x%x sec_state:%d",
btm_pair_state_descr(btm_cb.pairing_state), p_dev_rec->sm4,
p_dev_rec->sec_state);
} else {
# 我这边看的是BR/EDR 流程,走到这里 !
/* both local and peer are 2.1 */
status = btm_sec_dd_create_conn(p_dev_rec);
}
if (status != BTM_CMD_STARTED) {
BTM_TRACE_ERROR(
"%s BTM_ReadRemoteDeviceName or btm_sec_dd_create_conn error: 0x%x",
__func__, (int)status);
btm_sec_change_pairing_state(BTM_PAIR_STATE_IDLE);
}
return status;
}
这个接口很长,后面有发现学到的细节继续补充
下面实现建立ACL连接【ACL(AsynchronousConnectionless),和另一种链路是SCO(Synchronous Connection Oriented)。SCO主要用于同步话音传送,ACL主要用于分组数据传送】
ACL细节参考ACL&SCO链路介绍
system/bt/stack/btm/btm_sec.cc
/*******************************************************************************
*
* Function btm_sec_dd_create_conn
*
* Description This function is called to create the ACL connection for
* the dedicated boding process
*
* Returns void
*
******************************************************************************/
static tBTM_STATUS btm_sec_dd_create_conn(tBTM_SEC_DEV_REC* p_dev_rec) {
# Step1 找到一个lcb(link control block)
tL2C_LCB* p_lcb =
l2cu_find_lcb_by_bd_addr(p_dev_rec->bd_addr, BT_TRANSPORT_BR_EDR);
if (p_lcb && (p_lcb->link_state == LST_CONNECTED ||
p_lcb->link_state == LST_CONNECTING)) {
BTM_TRACE_WARNING("%s Connection already exists", __func__);
btm_sec_change_pairing_state(BTM_PAIR_STATE_WAIT_PIN_REQ);
return BTM_CMD_STARTED;
}
# Step2 确保l2cap lcb空闲
/* Make sure an L2cap link control block is available */
if (!p_lcb && (p_lcb = l2cu_allocate_lcb(p_dev_rec->bd_addr, true,
BT_TRANSPORT_BR_EDR)) == NULL) {
LOG(WARNING) << "Security Manager: failed allocate LCB "
<< p_dev_rec->bd_addr;
return (BTM_NO_RESOURCES);
}
/* set up the control block to indicated dedicated bonding */
btm_cb.pairing_flags |= BTM_PAIR_FLAGS_DISC_WHEN_DONE;
# Step3 通过HCI创建一个与经典蓝牙设备的ACL链接
if (!l2cu_create_conn_br_edr(p_lcb)) {
LOG(WARNING) << "Security Manager: failed create allocate LCB "
<< p_dev_rec->bd_addr;
l2cu_release_lcb(p_lcb);
return (BTM_NO_RESOURCES);
}
btm_acl_update_busy_level(BTM_BLI_PAGE_EVT);
VLOG(1) << "Security Manager: " << p_dev_rec->bd_addr;
btm_sec_change_pairing_state(BTM_PAIR_STATE_WAIT_PIN_REQ);
return (BTM_CMD_STARTED);
}
system/bt/stack/l2cap/l2c_utils.cc
----------------------------------------------
/* This function initiates an acl connection to a Classic device via HCI.
* Returns true on success, false otherwise. */
bool l2cu_create_conn_br_edr(tL2C_LCB* p_lcb) {
int xx;
tL2C_LCB* p_lcb_cur = &l2cb.lcb_pool[0];
bool is_sco_active;
/* If there is a connection where we perform as a slave, try to switch roles
for this connection */
for (xx = 0, p_lcb_cur = &l2cb.lcb_pool[0]; xx < MAX_L2CAP_LINKS;
xx++, p_lcb_cur++) {
if (p_lcb_cur == p_lcb) continue;
if ((p_lcb_cur->in_use) && (p_lcb_cur->link_role == HCI_ROLE_SLAVE)) {
/* The LMP_switch_req shall be sent only if the ACL logical transport
is in active mode, when encryption is disabled, and all synchronous
logical transports on the same physical link are disabled." */
/* Check if there is any SCO Active on this BD Address */
is_sco_active = btm_is_sco_active_by_bdaddr(p_lcb_cur->remote_bd_addr);
L2CAP_TRACE_API(
"l2cu_create_conn - btm_is_sco_active_by_bdaddr() is_sco_active = %s",
(is_sco_active) ? "true" : "false");
if (is_sco_active)
continue; /* No Master Slave switch not allowed when SCO Active */
/*4_1_TODO check if btm_cb.devcb.local_features to be used instead */
if (HCI_SWITCH_SUPPORTED(BTM_ReadLocalFeatures())) {
/* mark this lcb waiting for switch to be completed and
start switch on the other one */
p_lcb->link_state = LST_CONNECTING_WAIT_SWITCH;
p_lcb->link_role = HCI_ROLE_MASTER;
if (BTM_SwitchRole(p_lcb_cur->remote_bd_addr, HCI_ROLE_MASTER, NULL) ==
BTM_CMD_STARTED) {
alarm_set_on_mloop(p_lcb->l2c_lcb_timer,
L2CAP_LINK_ROLE_SWITCH_TIMEOUT_MS,
l2c_lcb_timer_timeout, p_lcb);
return (true);
}
}
}
}
p_lcb->link_state = LST_CONNECTING;
return (l2cu_create_conn_after_switch(p_lcb));
}
/*******************************************************************************
*
* Function l2cu_create_conn_after_switch
*
* Description This function initiates an acl connection via HCI
* If switch required to create connection it is already done.
*
* Returns true if successful, false if get buffer fails.
*
******************************************************************************/
bool l2cu_create_conn_after_switch(tL2C_LCB* p_lcb) {
uint8_t allow_switch = HCI_CR_CONN_ALLOW_SWITCH;
tBTM_INQ_INFO* p_inq_info;
uint8_t page_scan_rep_mode;
uint8_t page_scan_mode;
uint16_t clock_offset;
uint8_t* p_features;
uint16_t num_acl = BTM_GetNumAclLinks();
tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(p_lcb->remote_bd_addr);
uint8_t no_hi_prio_chs = l2cu_get_num_hi_priority();
p_features = BTM_ReadLocalFeatures();
L2CAP_TRACE_DEBUG(
"l2cu_create_conn_after_switch :%d num_acl:%d no_hi: %d is_bonding:%d",
l2cb.disallow_switch, num_acl, no_hi_prio_chs, p_lcb->is_bonding);
/* FW team says that we can participant in 4 piconets
* typically 3 piconet + 1 for scanning.
* We can enhance the code to count the number of piconets later. */
if (((!l2cb.disallow_switch && (num_acl < 3)) ||
(p_lcb->is_bonding && (no_hi_prio_chs == 0))) &&
HCI_SWITCH_SUPPORTED(p_features))
allow_switch = HCI_CR_CONN_ALLOW_SWITCH;
else
allow_switch = HCI_CR_CONN_NOT_ALLOW_SWITCH;
p_lcb->link_state = LST_CONNECTING;
/* Check with the BT manager if details about remote device are known */
p_inq_info = BTM_InqDbRead(p_lcb->remote_bd_addr);
if ((p_inq_info != NULL) &&
(p_inq_info->results.inq_result_type & BTM_INQ_RESULT_BR)) {
page_scan_rep_mode = p_inq_info->results.page_scan_rep_mode;
page_scan_mode = p_inq_info->results.page_scan_mode;
clock_offset = (uint16_t)(p_inq_info->results.clock_offset);
} else {
/* No info known. Use default settings */
page_scan_rep_mode = HCI_PAGE_SCAN_REP_MODE_R1;
page_scan_mode = HCI_MANDATARY_PAGE_SCAN_MODE;
clock_offset = (p_dev_rec) ? p_dev_rec->clock_offset : 0;
}
# 发起连接
btsnd_hcic_create_conn(
p_lcb->remote_bd_addr, (HCI_PKT_TYPES_MASK_DM1 | HCI_PKT_TYPES_MASK_DH1 |
HCI_PKT_TYPES_MASK_DM3 | HCI_PKT_TYPES_MASK_DH3 |
HCI_PKT_TYPES_MASK_DM5 | HCI_PKT_TYPES_MASK_DH5),
page_scan_rep_mode, page_scan_mode, clock_offset, allow_switch);
btm_acl_update_busy_level(BTM_BLI_PAGE_EVT);
# 设置定时器,l2c_lcb_timer_timeout进行超时处理;
alarm_set_on_mloop(p_lcb->l2c_lcb_timer, L2CAP_LINK_CONNECT_TIMEOUT_MS,
l2c_lcb_timer_timeout, p_lcb);
return (true);
}
void btsnd_hcic_create_conn(const RawAddress& dest, uint16_t packet_types,
uint8_t page_scan_rep_mode, uint8_t page_scan_mode,
uint16_t clock_offset, uint8_t allow_switch) {
BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
uint8_t* pp = (uint8_t*)(p + 1);
#ifndef BT_10A
p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_CREATE_CONN;
#else
p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_CREATE_CONN - 1;
#endif
p->offset = 0;
UINT16_TO_STREAM(pp, HCI_CREATE_CONNECTION);
#ifndef BT_10A
UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_CREATE_CONN);
#else
UINT8_TO_STREAM(pp, (HCIC_PARAM_SIZE_CREATE_CONN - 1));
#endif
BDADDR_TO_STREAM(pp, dest);
UINT16_TO_STREAM(pp, packet_types);
UINT8_TO_STREAM(pp, page_scan_rep_mode);
UINT8_TO_STREAM(pp, page_scan_mode);
UINT16_TO_STREAM(pp, clock_offset);
#if !defined(BT_10A)
UINT8_TO_STREAM(pp, allow_switch);
#endif
btm_acl_paging(p, dest);
}
/*******************************************************************************
*
* Function btm_acl_paging
*
* Description send a paging command or queue it in btm_cb
*
******************************************************************************/
void btm_acl_paging(BT_HDR* p, const RawAddress& bda) {
tBTM_SEC_DEV_REC* p_dev_rec;
VLOG(2) << __func__ << ":" << btm_cb.discing << " , paging:" << btm_cb.paging
<< " BDA: " << bda;
if (btm_cb.discing) {
btm_cb.paging = true;
fixed_queue_enqueue(btm_cb.page_queue, p);
} else {
if (!BTM_ACL_IS_CONNECTED(bda)) {
VLOG(1) << "connecting_bda: " << btm_cb.connecting_bda;
if (btm_cb.paging && bda == btm_cb.connecting_bda) {
fixed_queue_enqueue(btm_cb.page_queue, p);
} else {
p_dev_rec = btm_find_or_alloc_dev(bda);
btm_cb.connecting_bda = p_dev_rec->bd_addr;
memcpy(btm_cb.connecting_dc, p_dev_rec->dev_class, DEV_CLASS_LEN);
btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
}
btm_cb.paging = true;
} else /* ACL is already up */
{
# 发送了 HCIC_PARAM_SIZE_CREATE_CONN 命令
btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
}
}
}
/*******************************************************************************
*
* Function btu_hcif_send_cmd
*
* Description This function is called to send commands to the Host
* Controller.
*
* Returns void
*
******************************************************************************/
void btu_hcif_send_cmd(UNUSED_ATTR uint8_t controller_id, BT_HDR* p_buf) {
if (!p_buf) return;
uint16_t opcode;
uint8_t* stream = p_buf->data + p_buf->offset;
void* vsc_callback = NULL;
STREAM_TO_UINT16(opcode, stream);
// Eww...horrible hackery here
/* If command was a VSC, then extract command_complete callback */
if ((opcode & HCI_GRP_VENDOR_SPECIFIC) == HCI_GRP_VENDOR_SPECIFIC ||
(opcode == HCI_BLE_RAND) || (opcode == HCI_BLE_ENCRYPT)) {
vsc_callback = *((void**)(p_buf + 1));
}
// Skip parameter length before logging
stream++;
btu_hcif_log_command_metrics(opcode, stream,
android::bluetooth::hci::STATUS_UNKNOWN, false);
# 通过HCI向controller发送指令
hci_layer_get_interface()->transmit_command(
p_buf, btu_hcif_command_complete_evt, btu_hcif_command_status_evt,
vsc_callback);
}
transmit_comman发送机制参考[init_layer_interface]
|