/******************************************************************************* ** ** Function l2cble_set_fixed_channel_tx_data_length ** ** Description This function update max fixed channel tx data length if applicable ** ** Returns void ** *******************************************************************************/ void l2cble_set_fixed_channel_tx_data_length(BD_ADDR remote_bda, UINT16 fix_cid, UINT16 tx_mtu) { tL2C_LCB *p_lcb = l2cu_find_lcb_by_bd_addr(remote_bda, BT_TRANSPORT_LE); UINT16 cid = fix_cid - L2CAP_FIRST_FIXED_CHNL; L2CAP_TRACE_DEBUG("%s TX MTU = %d", __FUNCTION__, tx_mtu); if (!controller_get_interface()->supports_ble_packet_extension()) { L2CAP_TRACE_WARNING("%s, request not supported", __FUNCTION__); return; } /* See if we have a link control block for the connection */ if (p_lcb == NULL) return; if (p_lcb->p_fixed_ccbs[cid] != NULL) { if (tx_mtu > BTM_BLE_DATA_SIZE_MAX) tx_mtu = BTM_BLE_DATA_SIZE_MAX; p_lcb->p_fixed_ccbs[cid]->tx_data_len = tx_mtu; } l2cble_update_data_length(p_lcb); }
/******************************************************************************* ** ** Function L2CA_UpdateBleConnParams ** ** Description Update BLE connection parameters. ** ** Parameters: BD Address of remote ** ** Return value: TRUE if update started ** *******************************************************************************/ BOOLEAN L2CA_UpdateBleConnParams (BD_ADDR rem_bda, UINT16 min_int, UINT16 max_int, UINT16 latency, UINT16 timeout) { tL2C_LCB *p_lcb; /* See if we have a link control block for the remote device */ p_lcb = l2cu_find_lcb_by_bd_addr (rem_bda); /* If we don't have one, create one and accept the connection. */ if (!p_lcb) { L2CAP_TRACE_WARNING2 ("L2CA_UpdateBleConnParams - unknown BD_ADDR %08x%04x", (rem_bda[0]<<24)+(rem_bda[1]<<16)+(rem_bda[2]<<8)+rem_bda[3], (rem_bda[4]<<8)+rem_bda[5]); return(FALSE); } if (!p_lcb->is_ble_link) { L2CAP_TRACE_WARNING2 ("L2CA_UpdateBleConnParams - BD_ADDR %08x%04x not LE", (rem_bda[0]<<24)+(rem_bda[1]<<16)+(rem_bda[2]<<8)+rem_bda[3], (rem_bda[4]<<8)+rem_bda[5]); return(FALSE); } if (p_lcb->link_role == HCI_ROLE_MASTER) btsnd_hcic_ble_upd_ll_conn_params (p_lcb->handle, min_int, max_int, latency, timeout, 0, 0); else l2cu_send_peer_ble_par_req (p_lcb, min_int, max_int, latency, timeout); return(TRUE); }
/******************************************************************************* ** ** Function L2CA_UCDSetTxPriority ** ** Description Sets the transmission priority for a connectionless channel. ** ** Returns TRUE if a valid channel, else FALSE ** *******************************************************************************/ BOOLEAN L2CA_UCDSetTxPriority ( BD_ADDR rem_bda, tL2CAP_CHNL_PRIORITY priority ) { tL2C_LCB *p_lcb; tL2C_CCB *p_ccb; L2CAP_TRACE_API ("L2CA_UCDSetTxPriority() priority: 0x%02x BDA: %08x%04x", priority, (rem_bda[0] << 24) + (rem_bda[1] << 16) + (rem_bda[2] << 8) + rem_bda[3], (rem_bda[4] << 8) + rem_bda[5]); if ((p_lcb = l2cu_find_lcb_by_bd_addr (rem_bda, BT_TRANSPORT_BR_EDR)) == NULL) { L2CAP_TRACE_WARNING ("L2CAP - no LCB for L2CA_UCDSetTxPriority"); return (FALSE); } /* Find the channel control block */ if ((p_ccb = l2cu_find_ccb_by_cid (p_lcb, L2CAP_CONNECTIONLESS_CID)) == NULL) { L2CAP_TRACE_WARNING ("L2CAP - no CCB for L2CA_UCDSetTxPriority"); return (FALSE); } /* it will update the order of CCB in LCB by priority and update round robin service variables */ l2cu_change_pri_ccb (p_ccb, priority); return (TRUE); }
/******************************************************************************* ** ** Function L2CA_EnableUpdateBleConnParams ** ** Description Enable or disable update based on the request from the peer ** ** Parameters: BD Address of remote ** ** Return value: TRUE if update started ** *******************************************************************************/ BOOLEAN L2CA_EnableUpdateBleConnParams (BD_ADDR rem_bda, BOOLEAN enable) { tL2C_LCB *p_lcb; /* See if we have a link control block for the remote device */ p_lcb = l2cu_find_lcb_by_bd_addr (rem_bda); /* If we don't have one, create one and accept the connection. */ if (!p_lcb) { L2CAP_TRACE_WARNING2 ("L2CA_EnableUpdateBleConnParams - unknown BD_ADDR %08x%04x", (rem_bda[0]<<24)+(rem_bda[1]<<16)+(rem_bda[2]<<8)+rem_bda[3], (rem_bda[4]<<8)+rem_bda[5]); return (FALSE); } L2CAP_TRACE_API4 ("L2CA_EnableUpdateBleConnParams - BD_ADDR %08x%04x enable %d current upd state %d", (rem_bda[0]<<24)+(rem_bda[1]<<16)+(rem_bda[2]<<8)+rem_bda[3], (rem_bda[4]<<8)+rem_bda[5], enable, p_lcb->upd_disabled); if (!p_lcb->is_ble_link || (p_lcb->link_role != HCI_ROLE_MASTER)) { L2CAP_TRACE_WARNING3 ("L2CA_EnableUpdateBleConnParams - BD_ADDR %08x%04x not LE or not master %d", (rem_bda[0]<<24)+(rem_bda[1]<<16)+(rem_bda[2]<<8)+rem_bda[3], (rem_bda[4]<<8)+rem_bda[5], p_lcb->link_role); return (FALSE); } if (enable) { /* application allows to do update, if we were delaying one do it now, otherwise just mark lcb that updates are enabled */ if (p_lcb->upd_disabled == UPD_PENDING) { btsnd_hcic_ble_upd_ll_conn_params (p_lcb->handle, p_lcb->min_interval, p_lcb->max_interval, p_lcb->latency, p_lcb->timeout, 0, 0); p_lcb->upd_disabled = UPD_UPDATED; } else { p_lcb->upd_disabled = UPD_ENABLED; } } else { /* application requests to disable parameters update. If parameters are already updated, lets set them up to what has been requested during connection establishement */ if (p_lcb->upd_disabled == UPD_UPDATED) { tBTM_SEC_DEV_REC *p_dev_rec = btm_find_or_alloc_dev (rem_bda); btsnd_hcic_ble_upd_ll_conn_params (p_lcb->handle, (UINT16)((p_dev_rec->conn_params.min_conn_int != BTM_BLE_CONN_PARAM_UNDEF) ? p_dev_rec->conn_params.min_conn_int : BTM_BLE_CONN_INT_MIN_DEF), (UINT16)((p_dev_rec->conn_params.max_conn_int != BTM_BLE_CONN_PARAM_UNDEF) ? p_dev_rec->conn_params.max_conn_int : BTM_BLE_CONN_INT_MAX_DEF), (UINT16)((p_dev_rec->conn_params.slave_latency != BTM_BLE_CONN_PARAM_UNDEF) ? p_dev_rec->conn_params.slave_latency : BTM_BLE_CONN_SLAVE_LATENCY_DEF), (UINT16) ((p_dev_rec->conn_params.supervision_tout != BTM_BLE_CONN_PARAM_UNDEF) ? p_dev_rec->conn_params.supervision_tout : BTM_BLE_CONN_TIMEOUT_DEF), 0, 0); } p_lcb->upd_disabled = UPD_DISABLED; } return (TRUE); }
/******************************************************************************* ** ** Function L2CA_GetBleConnRole ** ** Description This function returns the connection role. ** ** Returns link role. ** *******************************************************************************/ UINT8 L2CA_GetBleConnRole (BD_ADDR bd_addr) { UINT8 role = HCI_ROLE_UNKNOWN; tL2C_LCB *p_lcb; if ((p_lcb = l2cu_find_lcb_by_bd_addr (bd_addr)) != NULL) role = p_lcb->link_role; return role; }
/******************************************************************************* ** ** Function L2CA_GetDisconnectReason ** ** Description This function returns the disconnect reason code. ** ** Returns disconnect reason ** *******************************************************************************/ UINT16 L2CA_GetDisconnectReason (BD_ADDR remote_bda) { tL2C_LCB *p_lcb; UINT16 reason = 0; if ((p_lcb = l2cu_find_lcb_by_bd_addr (remote_bda)) != NULL) reason = p_lcb->disc_reason; L2CAP_TRACE_DEBUG1 ("L2CA_GetDisconnectReason=%d ",reason); return reason; }
/******************************************************************************* ** ** Function l2cble_notify_le_connection ** ** Description This function notifiy the l2cap connection to the app layer ** ** Returns none ** *******************************************************************************/ void l2cble_notify_le_connection (BD_ADDR bda) { tL2C_LCB *p_lcb = l2cu_find_lcb_by_bd_addr (bda, BT_TRANSPORT_LE); tACL_CONN *p_acl = btm_bda_to_acl(bda, BT_TRANSPORT_LE) ; if (p_lcb != NULL && p_acl != NULL && p_lcb->link_state != LST_CONNECTED) { /* update link status */ btm_establish_continue(p_acl); /* update l2cap link status and send callback */ p_lcb->link_state = LST_CONNECTED; l2cu_process_fixed_chnl_resp (p_lcb); } }
/******************************************************************************* ** ** Function l2cble_advertiser_conn_comp ** ** Description This function is called when an HCI Connection Complete ** event is received while we are an advertiser (so we are slave). ** ** Returns void ** *******************************************************************************/ void l2cble_advertiser_conn_comp (UINT16 handle, BD_ADDR bda, tBLE_ADDR_TYPE type, UINT16 conn_interval, UINT16 conn_latency, UINT16 conn_timeout) { tL2C_LCB *p_lcb; tBTM_SEC_DEV_REC *p_dev_rec; /* See if we have a link control block for the remote device */ p_lcb = l2cu_find_lcb_by_bd_addr (bda); /* If we don't have one, create one and accept the connection. */ if (!p_lcb) { p_lcb = l2cu_allocate_lcb (bda, FALSE); if (!p_lcb) { btm_sec_disconnect (handle, HCI_ERR_NO_CONNECTION); L2CAP_TRACE_ERROR0 ("l2cble_advertiser_conn_comp - failed to allocate LCB"); return; } else { if (!l2cu_initialize_fixed_ccb (p_lcb, L2CAP_ATT_CID, &l2cb.fixed_reg[L2CAP_ATT_CID - L2CAP_FIRST_FIXED_CHNL].fixed_chnl_opts)) { btm_sec_disconnect (handle, HCI_ERR_NO_CONNECTION); L2CAP_TRACE_WARNING0 ("l2cble_scanner_conn_comp - LCB but no CCB"); return ; } } } /* Save the handle */ p_lcb->handle = handle; /* Connected OK. Change state to connected, we were advertising, so we are slave */ p_lcb->link_state = LST_CONNECTED; p_lcb->link_role = HCI_ROLE_SLAVE; p_lcb->is_ble_link = TRUE; /* Tell BTM Acl management about the link */ p_dev_rec = btm_find_or_alloc_dev (bda); btm_acl_created (bda, NULL, p_dev_rec->sec_bd_name, handle, p_lcb->link_role, TRUE); p_lcb->peer_chnl_mask[0] = L2CAP_FIXED_CHNL_ATT_BIT | L2CAP_FIXED_CHNL_BLE_SIG_BIT | L2CAP_FIXED_CHNL_SMP_BIT; l2cu_process_fixed_chnl_resp (p_lcb); }
/******************************************************************************* ** ** Function L2CA_UcdDiscover ** ** Description Discover UCD of remote device. ** ** Parameters: PSM ** BD_ADDR of remote device ** info_type : L2CAP_UCD_INFO_TYPE_RECEPTION ** L2CAP_UCD_INFO_TYPE_MTU ** ** ** Return value: TRUE if successs ** *******************************************************************************/ BOOLEAN L2CA_UcdDiscover ( UINT16 psm, BD_ADDR rem_bda, UINT8 info_type ) { tL2C_LCB *p_lcb; tL2C_CCB *p_ccb; tL2C_RCB *p_rcb; L2CAP_TRACE_API ("L2CA_UcdDiscover() PSM: 0x%04x BDA: %08x%04x, InfoType=0x%02x", psm, (rem_bda[0] << 24) + (rem_bda[1] << 16) + (rem_bda[2] << 8) + rem_bda[3], (rem_bda[4] << 8) + rem_bda[5], info_type); /* Fail if the PSM is not registered */ if (((p_rcb = l2cu_find_rcb_by_psm (psm)) == NULL) || ( p_rcb->ucd.state == L2C_UCD_STATE_UNUSED )) { L2CAP_TRACE_WARNING ("L2CAP - no RCB for L2CA_UcdDiscover, PSM: 0x%04x", psm); return (FALSE); } /* First, see if we already have a link to the remote */ /* then find the channel control block for UCD. */ if (((p_lcb = l2cu_find_lcb_by_bd_addr (rem_bda, BT_TRANSPORT_BR_EDR)) == NULL) || ((p_ccb = l2cu_find_ccb_by_cid (p_lcb, L2CAP_CONNECTIONLESS_CID)) == NULL)) { if ( l2c_ucd_connect (rem_bda) == FALSE ) { return (FALSE); } } /* set waiting flags in rcb */ if ( info_type & L2CAP_UCD_INFO_TYPE_RECEPTION ) { p_rcb->ucd.state |= L2C_UCD_STATE_W4_RECEPTION; } if ( info_type & L2CAP_UCD_INFO_TYPE_MTU ) { p_rcb->ucd.state |= L2C_UCD_STATE_W4_MTU; } /* if link is already established */ if ((p_lcb) && (p_lcb->link_state == LST_CONNECTED)) { if (!p_ccb) { p_ccb = l2cu_find_ccb_by_cid (p_lcb, L2CAP_CONNECTIONLESS_CID); } l2c_ucd_check_pending_info_req(p_ccb); } return (TRUE); }
/******************************************************************************* ** ** Function L2CA_CancelBleConnectReq ** ** Description Cancel a pending connection attempt to a BLE device. ** ** Parameters: BD Address of remote ** ** Return value: TRUE if connection was cancelled ** *******************************************************************************/ BOOLEAN L2CA_CancelBleConnectReq (BD_ADDR rem_bda) { tL2C_LCB *p_lcb; BOOLEAN rem_lcb = TRUE; /* There can be only one BLE connection request outstanding at a time */ if (btm_ble_get_conn_st() == BLE_CONN_IDLE) { L2CAP_TRACE_WARNING ("L2CA_CancelBleConnectReq - no connection pending"); return(FALSE); } if (memcmp (rem_bda, l2cb.ble_connecting_bda, BD_ADDR_LEN)) { L2CAP_TRACE_WARNING ("L2CA_CancelBleConnectReq - different BDA Connecting: %08x%04x Cancel: %08x%04x", (l2cb.ble_connecting_bda[0]<<24)+(l2cb.ble_connecting_bda[1]<<16)+(l2cb.ble_connecting_bda[2]<<8)+l2cb.ble_connecting_bda[3], (l2cb.ble_connecting_bda[4]<<8)+l2cb.ble_connecting_bda[5], (rem_bda[0]<<24)+(rem_bda[1]<<16)+(rem_bda[2]<<8)+rem_bda[3], (rem_bda[4]<<8)+rem_bda[5]); btm_ble_dequeue_direct_conn_req(rem_bda); return(FALSE); } if (btsnd_hcic_ble_create_conn_cancel()) { p_lcb = l2cu_find_lcb_by_bd_addr(rem_bda, BT_TRANSPORT_LE); /*Do not remove lcb if a LE link is already up as peripheral*/ if(p_lcb != NULL && p_lcb->link_role == HCI_ROLE_SLAVE && BTM_ACL_IS_CONNECTED(rem_bda)) { rem_lcb = FALSE; } if (rem_lcb && p_lcb != NULL) { p_lcb->disc_reason = L2CAP_CONN_CANCEL; l2cu_release_lcb (p_lcb); } /* update state to be cancel, wait for connection cancel complete */ btm_ble_set_conn_st (BLE_CONN_CANCEL); return(TRUE); } else return(FALSE); }
/******************************************************************************* ** ** Function L2CA_UcdSetIdleTimeout ** ** Description Set UCD Idle timeout. ** ** Parameters: BD Addr ** Timeout in second ** ** Return value: TRUE if successs ** *******************************************************************************/ BOOLEAN L2CA_UcdSetIdleTimeout ( BD_ADDR rem_bda, UINT16 timeout ) { tL2C_LCB *p_lcb; tL2C_CCB *p_ccb; L2CAP_TRACE_API ("L2CA_UcdSetIdleTimeout() Timeout: 0x%04x BDA: %08x%04x", timeout, (rem_bda[0] << 24) + (rem_bda[1] << 16) + (rem_bda[2] << 8) + rem_bda[3], (rem_bda[4] << 8) + rem_bda[5]); /* First, see if we already have a link to the remote */ /* then find the channel control block. */ if (((p_lcb = l2cu_find_lcb_by_bd_addr (rem_bda, BT_TRANSPORT_BR_EDR)) == NULL) || ((p_ccb = l2cu_find_ccb_by_cid (p_lcb, L2CAP_CONNECTIONLESS_CID)) == NULL)) { L2CAP_TRACE_WARNING ("L2CAP - no UCD channel"); return (FALSE); } else { p_ccb->fixed_chnl_idle_tout = timeout; return (TRUE); } }
/******************************************************************************* ** ** Function L2CA_CancelBleConnectReq ** ** Description Cancel a pending connection attempt to a BLE device. ** ** Parameters: BD Address of remote ** ** Return value: TRUE if connection was cancelled ** *******************************************************************************/ BOOLEAN L2CA_CancelBleConnectReq (BD_ADDR rem_bda) { tL2C_LCB *p_lcb; /* There can be only one BLE connection request outstanding at a time */ //changed check for BLE_CONN_IDLE instead of incorrect BLE_DIR_CONN for no pending connection if (btm_ble_get_conn_st() == BLE_CONN_IDLE) { L2CAP_TRACE_WARNING0 ("L2CA_CancelBleConnectReq - no connection pending"); return(FALSE); } if (memcmp (rem_bda, l2cb.ble_connecting_bda, BD_ADDR_LEN)) { L2CAP_TRACE_WARNING4 ("L2CA_CancelBleConnectReq - different BDA Connecting: %08x%04x Cancel: %08x%04x", (l2cb.ble_connecting_bda[0]<<24)+(l2cb.ble_connecting_bda[1]<<16)+(l2cb.ble_connecting_bda[2]<<8)+l2cb.ble_connecting_bda[3], (l2cb.ble_connecting_bda[4]<<8)+l2cb.ble_connecting_bda[5], (rem_bda[0]<<24)+(rem_bda[1]<<16)+(rem_bda[2]<<8)+rem_bda[3], (rem_bda[4]<<8)+rem_bda[5]); return(FALSE); } if (btsnd_hcic_ble_create_conn_cancel()) { if ((p_lcb = l2cu_find_lcb_by_bd_addr (rem_bda)) != NULL) { p_lcb->disc_reason = L2CAP_CONN_CANCEL; l2cu_release_lcb (p_lcb); } /* update conn state to IDLE */ btm_ble_set_conn_st (BLE_CONN_IDLE); return(TRUE); } else return(FALSE); }
/******************************************************************************* ** ** Function L2CA_UpdateBleConnParams ** ** Description Update BLE connection parameters. ** ** Parameters: BD Address of remote ** ** Return value: TRUE if update started ** *******************************************************************************/ BOOLEAN L2CA_UpdateBleConnParams (BD_ADDR rem_bda, UINT16 min_int, UINT16 max_int, UINT16 latency, UINT16 timeout) { tL2C_LCB *p_lcb; tACL_CONN *p_acl_cb = btm_bda_to_acl(rem_bda, BT_TRANSPORT_LE); /* See if we have a link control block for the remote device */ p_lcb = l2cu_find_lcb_by_bd_addr (rem_bda, BT_TRANSPORT_LE); /* If we don't have one, create one and accept the connection. */ if (!p_lcb || !p_acl_cb) { L2CAP_TRACE_WARNING ("L2CA_UpdateBleConnParams - unknown BD_ADDR %08x%04x", (rem_bda[0]<<24)+(rem_bda[1]<<16)+(rem_bda[2]<<8)+rem_bda[3], (rem_bda[4]<<8)+rem_bda[5]); return(FALSE); } if (p_lcb->transport != BT_TRANSPORT_LE) { L2CAP_TRACE_WARNING ("L2CA_UpdateBleConnParams - BD_ADDR %08x%04x not LE", (rem_bda[0]<<24)+(rem_bda[1]<<16)+(rem_bda[2]<<8)+rem_bda[3], (rem_bda[4]<<8)+rem_bda[5]); return(FALSE); } p_lcb->min_interval = min_int; p_lcb->max_interval = max_int; p_lcb->latency = latency; p_lcb->timeout = timeout; p_lcb->conn_update_mask |= L2C_BLE_NEW_CONN_PARAM; l2cble_start_conn_update(p_lcb); return(TRUE); }
/******************************************************************************* ** ** Function L2CA_EnableUpdateBleConnParams ** ** Description Enable or disable update based on the request from the peer ** ** Parameters: BD Address of remote ** ** Return value: TRUE if update started ** *******************************************************************************/ BOOLEAN L2CA_EnableUpdateBleConnParams (BD_ADDR rem_bda, BOOLEAN enable) { tL2C_LCB *p_lcb; /* See if we have a link control block for the remote device */ p_lcb = l2cu_find_lcb_by_bd_addr (rem_bda, BT_TRANSPORT_LE); if (!p_lcb) { L2CAP_TRACE_WARNING ("L2CA_EnableUpdateBleConnParams - unknown BD_ADDR %08x%04x", (rem_bda[0]<<24)+(rem_bda[1]<<16)+(rem_bda[2]<<8)+rem_bda[3], (rem_bda[4]<<8)+rem_bda[5]); return (FALSE); } L2CAP_TRACE_API ("%s - BD_ADDR %08x%04x enable %d current upd state 0x%02x",__FUNCTION__, (rem_bda[0]<<24)+(rem_bda[1]<<16)+(rem_bda[2]<<8)+rem_bda[3], (rem_bda[4]<<8)+rem_bda[5], enable, p_lcb->conn_update_mask); if (p_lcb->transport != BT_TRANSPORT_LE) { L2CAP_TRACE_WARNING ("%s - BD_ADDR %08x%04x not LE (link role %d)", __FUNCTION__, (rem_bda[0]<<24)+(rem_bda[1]<<16)+(rem_bda[2]<<8)+rem_bda[3], (rem_bda[4]<<8)+rem_bda[5], p_lcb->link_role); return (FALSE); } if (enable) p_lcb->conn_update_mask &= ~L2C_BLE_CONN_UPDATE_DISABLE; else p_lcb->conn_update_mask |= L2C_BLE_CONN_UPDATE_DISABLE; l2cble_start_conn_update(p_lcb); return (TRUE); }
/******************************************************************************* ** ** Function L2CA_UcdDataWrite ** ** Description Send UCD to remote device ** ** Parameters: PSM ** BD Address of remote ** Pointer to buffer of type BT_HDR ** flags : L2CAP_FLUSHABLE_CH_BASED ** L2CAP_FLUSHABLE_PKT ** L2CAP_NON_FLUSHABLE_PKT ** ** Return value L2CAP_DW_SUCCESS, if data accepted ** L2CAP_DW_FAILED, if error ** *******************************************************************************/ UINT16 L2CA_UcdDataWrite (UINT16 psm, BD_ADDR rem_bda, BT_HDR *p_buf, UINT16 flags) { tL2C_LCB *p_lcb; tL2C_CCB *p_ccb; tL2C_RCB *p_rcb; UINT8 *p; L2CAP_TRACE_API ("L2CA_UcdDataWrite() PSM: 0x%04x BDA: %08x%04x", psm, (rem_bda[0] << 24) + (rem_bda[1] << 16) + (rem_bda[2] << 8) + rem_bda[3], (rem_bda[4] << 8) + rem_bda[5]); /* Fail if the PSM is not registered */ if (((p_rcb = l2cu_find_rcb_by_psm (psm)) == NULL) || ( p_rcb->ucd.state == L2C_UCD_STATE_UNUSED )) { L2CAP_TRACE_WARNING ("L2CAP - no RCB for L2CA_UcdDataWrite, PSM: 0x%04x", psm); osi_free (p_buf); return (L2CAP_DW_FAILED); } /* First, see if we already have a link to the remote */ /* then find the channel control block for UCD */ if (((p_lcb = l2cu_find_lcb_by_bd_addr (rem_bda, BT_TRANSPORT_BR_EDR)) == NULL) || ((p_ccb = l2cu_find_ccb_by_cid (p_lcb, L2CAP_CONNECTIONLESS_CID)) == NULL)) { if ( l2c_ucd_connect (rem_bda) == FALSE ) { osi_free (p_buf); return (L2CAP_DW_FAILED); } /* If we still don't have lcb and ccb after connect attempt, then can't proceed */ if (((p_lcb = l2cu_find_lcb_by_bd_addr (rem_bda, BT_TRANSPORT_BR_EDR)) == NULL) || ((p_ccb = l2cu_find_ccb_by_cid (p_lcb, L2CAP_CONNECTIONLESS_CID)) == NULL)) { osi_free (p_buf); return (L2CAP_DW_FAILED); } } /* write PSM */ p_buf->offset -= L2CAP_UCD_OVERHEAD; p_buf->len += L2CAP_UCD_OVERHEAD; p = (UINT8 *)(p_buf + 1) + p_buf->offset; UINT16_TO_STREAM (p, psm); /* UCD MTU check */ if ((p_lcb->ucd_mtu) && (p_buf->len > p_lcb->ucd_mtu)) { L2CAP_TRACE_WARNING ("L2CAP - Handle: 0x%04x UCD bigger than peer's UCD mtu size cannot be sent", p_lcb->handle); osi_free (p_buf); return (L2CAP_DW_FAILED); } /* If already congested, do not accept any more packets */ if (p_ccb->cong_sent) { L2CAP_TRACE_ERROR ("L2CAP - Handle: 0x%04x UCD cannot be sent, already congested count: %u buff_quota: %u", p_lcb->handle, (fixed_queue_length(p_ccb->xmit_hold_q) + fixed_queue_length(p_lcb->ucd_out_sec_pending_q)), p_ccb->buff_quota); osi_free (p_buf); return (L2CAP_DW_FAILED); } /* channel based, packet based flushable or non-flushable */ p_buf->layer_specific = flags; l2c_csm_execute (p_ccb, L2CEVT_L2CA_DATA_WRITE, p_buf); if (p_ccb->cong_sent) { return (L2CAP_DW_CONGESTED); } else { return (L2CAP_DW_SUCCESS); } }
/******************************************************************************* ** ** Function l2cble_advertiser_conn_comp ** ** Description This function is called when an HCI Connection Complete ** event is received while we are an advertiser (so we are slave). ** ** Returns void ** *******************************************************************************/ void l2cble_advertiser_conn_comp (UINT16 handle, BD_ADDR bda, tBLE_ADDR_TYPE type, UINT16 conn_interval, UINT16 conn_latency, UINT16 conn_timeout) { int i; tL2C_LCB *p_lcb; tBTM_SEC_DEV_REC *p_dev_rec; UNUSED(type); UNUSED(conn_interval); UNUSED(conn_latency); UNUSED(conn_timeout); /* See if we have a link control block for the remote device */ p_lcb = l2cu_find_lcb_by_bd_addr (bda, BT_TRANSPORT_LE); /* If we don't have one, create one and accept the connection. */ if (!p_lcb) { p_lcb = l2cu_allocate_lcb (bda, FALSE, BT_TRANSPORT_LE); if (!p_lcb) { btm_sec_disconnect (handle, HCI_ERR_NO_CONNECTION); L2CAP_TRACE_ERROR ("l2cble_advertiser_conn_comp - failed to allocate LCB"); return; } else { if (!l2cu_initialize_fixed_ccb (p_lcb, L2CAP_ATT_CID, &l2cb.fixed_reg[L2CAP_ATT_CID - L2CAP_FIRST_FIXED_CHNL].fixed_chnl_opts)) { btm_sec_disconnect (handle, HCI_ERR_NO_CONNECTION); L2CAP_TRACE_WARNING ("l2cble_scanner_conn_comp - LCB but no CCB"); return ; } } } /* Save the handle */ p_lcb->handle = handle; /* Connected OK. Change state to connected, we were advertising, so we are slave */ p_lcb->link_role = HCI_ROLE_SLAVE; p_lcb->transport = BT_TRANSPORT_LE; /* update link parameter, set slave link as non-spec default upon link up */ p_lcb->min_interval = p_lcb->max_interval = conn_interval; p_lcb->timeout = conn_timeout; p_lcb->latency = conn_latency; p_lcb->conn_update_mask = L2C_BLE_NOT_DEFAULT_PARAM; /* Tell BTM Acl management about the link */ p_dev_rec = btm_find_or_alloc_dev (bda); btm_acl_created (bda, NULL, p_dev_rec->sec_bd_name, handle, p_lcb->link_role, BT_TRANSPORT_LE); #if BLE_PRIVACY_SPT == TRUE btm_ble_disable_resolving_list(BTM_BLE_RL_ADV, TRUE); #endif p_lcb->peer_chnl_mask[0] = L2CAP_FIXED_CHNL_ATT_BIT | L2CAP_FIXED_CHNL_BLE_SIG_BIT | L2CAP_FIXED_CHNL_SMP_BIT; if (!HCI_LE_SLAVE_INIT_FEAT_EXC_SUPPORTED(controller_get_interface()->get_features_ble()->as_array)) { p_lcb->link_state = LST_CONNECTED; l2cu_process_fixed_chnl_resp (p_lcb); } /* when adv and initiating are both active, cancel the direct connection */ if (l2cb.is_ble_connecting && memcmp(bda, l2cb.ble_connecting_bda, BD_ADDR_LEN) == 0) { L2CA_CancelBleConnectReq(bda); } }
/******************************************************************************* ** ** Function l2c_ucd_connect ** ** Description Connect UCD to remote device. ** ** Parameters: BD_ADDR of remote device ** ** Return value: TRUE if successs ** *******************************************************************************/ static BOOLEAN l2c_ucd_connect ( BD_ADDR rem_bda ) { tL2C_LCB *p_lcb; tL2C_CCB *p_ccb; tL2C_RCB *p_rcb; L2CAP_TRACE_DEBUG ("l2c_ucd_connect() BDA: %08x%04x", (rem_bda[0] << 24) + (rem_bda[1] << 16) + (rem_bda[2] << 8) + rem_bda[3], (rem_bda[4] << 8) + rem_bda[5]); /* Fail if we have not established communications with the controller */ if (!BTM_IsDeviceUp()) { L2CAP_TRACE_WARNING ("l2c_ucd_connect - BTU not ready"); return (FALSE); } /* First, see if we already have a link to the remote */ if ((p_lcb = l2cu_find_lcb_by_bd_addr (rem_bda, BT_TRANSPORT_BR_EDR)) == NULL) { /* No link. Get an LCB and start link establishment */ if ( ((p_lcb = l2cu_allocate_lcb (rem_bda, FALSE, BT_TRANSPORT_BR_EDR)) == NULL) || (l2cu_create_conn(p_lcb, BT_TRANSPORT_BR_EDR) == FALSE) ) { L2CAP_TRACE_WARNING ("L2CAP - conn not started l2c_ucd_connect"); return (FALSE); } } else if ( p_lcb->info_rx_bits & (1 << L2CAP_EXTENDED_FEATURES_INFO_TYPE) ) { if (!(p_lcb->peer_ext_fea & L2CAP_EXTFEA_UCD_RECEPTION)) { L2CAP_TRACE_WARNING ("L2CAP - UCD is not supported by peer, l2c_ucd_connect"); return (FALSE); } } /* Find the channel control block. */ if ((p_ccb = l2cu_find_ccb_by_cid (p_lcb, L2CAP_CONNECTIONLESS_CID)) == NULL) { /* Allocate a channel control block */ if ((p_ccb = l2cu_allocate_ccb (p_lcb, 0)) == NULL) { L2CAP_TRACE_WARNING ("L2CAP - no CCB for l2c_ucd_connect"); return (FALSE); } else { /* Set CID for the connection */ p_ccb->local_cid = L2CAP_CONNECTIONLESS_CID; p_ccb->remote_cid = L2CAP_CONNECTIONLESS_CID; /* Set the default idle timeout value to use */ p_ccb->fixed_chnl_idle_tout = L2CAP_UCD_IDLE_TIMEOUT; /* Set the default channel priority value to use */ l2cu_change_pri_ccb (p_ccb, L2CAP_UCD_CH_PRIORITY); if ((p_rcb = l2cu_find_rcb_by_psm (L2C_UCD_RCB_ID)) == NULL) { L2CAP_TRACE_WARNING ("L2CAP - no UCD registered, l2c_ucd_connect"); return (FALSE); } /* Save UCD registration info */ p_ccb->p_rcb = p_rcb; /* There is no configuration, so if the link is up, the channel is up */ if (p_lcb->link_state == LST_CONNECTED) { p_ccb->chnl_state = CST_OPEN; } } } return (TRUE); }
/******************************************************************************* ** ** Function l2cble_scanner_conn_comp ** ** Description This function is called when an HCI Connection Complete ** event is received while we are a scanner (so we are master). ** ** Returns void ** *******************************************************************************/ void l2cble_scanner_conn_comp (UINT16 handle, BD_ADDR bda, tBLE_ADDR_TYPE type, UINT16 conn_interval, UINT16 conn_latency, UINT16 conn_timeout) { tL2C_LCB *p_lcb; tBTM_SEC_DEV_REC *p_dev_rec = btm_find_or_alloc_dev (bda); L2CAP_TRACE_DEBUG5 ("l2cble_scanner_conn_comp: HANDLE=%d addr_type=%d conn_interval=%d slave_latency=%d supervision_tout=%d", handle, type, conn_interval, conn_latency, conn_timeout); l2cb.is_ble_connecting = FALSE; /* See if we have a link control block for the remote device */ p_lcb = l2cu_find_lcb_by_bd_addr (bda); /* If we don't have one, create one. this is auto connection complete. */ if (!p_lcb) { p_lcb = l2cu_allocate_lcb (bda, FALSE); if (!p_lcb) { btm_sec_disconnect (handle, HCI_ERR_NO_CONNECTION); L2CAP_TRACE_ERROR0 ("l2cble_scanner_conn_comp - failed to allocate LCB"); return; } else { if (!l2cu_initialize_fixed_ccb (p_lcb, L2CAP_ATT_CID, &l2cb.fixed_reg[L2CAP_ATT_CID - L2CAP_FIRST_FIXED_CHNL].fixed_chnl_opts)) { btm_sec_disconnect (handle, HCI_ERR_NO_CONNECTION); L2CAP_TRACE_WARNING0 ("l2cble_scanner_conn_comp - LCB but no CCB"); return ; } } } else if (p_lcb->link_state != LST_CONNECTING) { L2CAP_TRACE_ERROR1 ("L2CAP got BLE scanner conn_comp in bad state: %d", p_lcb->link_state); return; } btu_stop_timer(&p_lcb->timer_entry); /* Save the handle */ p_lcb->handle = handle; /* Connected OK. Change state to connected, we were scanning so we are master */ p_lcb->link_state = LST_CONNECTED; p_lcb->link_role = HCI_ROLE_MASTER; p_lcb->is_ble_link = TRUE; /* If there are any preferred connection parameters, set them now */ if ( (p_dev_rec->conn_params.min_conn_int >= BTM_BLE_CONN_INT_MIN ) && (p_dev_rec->conn_params.min_conn_int <= BTM_BLE_CONN_INT_MAX ) && (p_dev_rec->conn_params.max_conn_int >= BTM_BLE_CONN_INT_MIN ) && (p_dev_rec->conn_params.max_conn_int <= BTM_BLE_CONN_INT_MAX ) && (p_dev_rec->conn_params.slave_latency <= BTM_BLE_CONN_LATENCY_MAX ) && (p_dev_rec->conn_params.supervision_tout >= BTM_BLE_CONN_SUP_TOUT_MIN) && (p_dev_rec->conn_params.supervision_tout <= BTM_BLE_CONN_SUP_TOUT_MAX) && ((conn_interval < p_dev_rec->conn_params.min_conn_int && p_dev_rec->conn_params.min_conn_int != BTM_BLE_CONN_PARAM_UNDEF) || (conn_interval > p_dev_rec->conn_params.max_conn_int) || (conn_latency > p_dev_rec->conn_params.slave_latency) || (conn_timeout > p_dev_rec->conn_params.supervision_tout))) { L2CAP_TRACE_ERROR5 ("upd_ll_conn_params: HANDLE=%d min_conn_int=%d max_conn_int=%d slave_latency=%d supervision_tout=%d", handle, p_dev_rec->conn_params.min_conn_int, p_dev_rec->conn_params.max_conn_int, p_dev_rec->conn_params.slave_latency, p_dev_rec->conn_params.supervision_tout); btsnd_hcic_ble_upd_ll_conn_params (handle, p_dev_rec->conn_params.min_conn_int, p_dev_rec->conn_params.max_conn_int, p_dev_rec->conn_params.slave_latency, p_dev_rec->conn_params.supervision_tout, 0, 0); } /* Tell BTM Acl management about the link */ btm_acl_created (bda, NULL, p_dev_rec->sec_bd_name, handle, p_lcb->link_role, TRUE); if (p_lcb->p_echo_rsp_cb) { L2CAP_TRACE_ERROR0 ("l2cu_send_peer_echo_req"); l2cu_send_peer_echo_req (p_lcb, NULL, 0); } p_lcb->peer_chnl_mask[0] = L2CAP_FIXED_CHNL_ATT_BIT | L2CAP_FIXED_CHNL_BLE_SIG_BIT | L2CAP_FIXED_CHNL_SMP_BIT; l2cu_process_fixed_chnl_resp (p_lcb); }