1171 lines
38 KiB
C
1171 lines
38 KiB
C
|
/******************************************************************************
|
||
|
*
|
||
|
* Copyright (C) 1999-2012 Broadcom Corporation
|
||
|
*
|
||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
* you may not use this file except in compliance with the License.
|
||
|
* You may obtain a copy of the License at:
|
||
|
*
|
||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||
|
*
|
||
|
* Unless required by applicable law or agreed to in writing, software
|
||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
* See the License for the specific language governing permissions and
|
||
|
* limitations under the License.
|
||
|
*
|
||
|
******************************************************************************/
|
||
|
|
||
|
/******************************************************************************
|
||
|
*
|
||
|
* This file contains the L2CAP UCD code
|
||
|
*
|
||
|
******************************************************************************/
|
||
|
|
||
|
#include <stdlib.h>
|
||
|
#include <string.h>
|
||
|
//#include <stdio.h>
|
||
|
|
||
|
#include "gki.h"
|
||
|
#include "bt_types.h"
|
||
|
#include "hcidefs.h"
|
||
|
#include "hcimsgs.h"
|
||
|
#include "l2cdefs.h"
|
||
|
#include "l2c_int.h"
|
||
|
#include "btu.h"
|
||
|
#include "btm_api.h"
|
||
|
#include "btm_int.h"
|
||
|
|
||
|
#if (L2CAP_UCD_INCLUDED == TRUE)
|
||
|
static BOOLEAN l2c_ucd_connect ( BD_ADDR rem_bda );
|
||
|
|
||
|
/*******************************************************************************
|
||
|
**
|
||
|
** Function l2c_ucd_discover_cback
|
||
|
**
|
||
|
** Description UCD Discover callback
|
||
|
**
|
||
|
** Returns void
|
||
|
**
|
||
|
*******************************************************************************/
|
||
|
static void l2c_ucd_discover_cback (BD_ADDR rem_bda, UINT8 info_type, UINT32 data)
|
||
|
{
|
||
|
tL2C_RCB *p_rcb = &l2cb.rcb_pool[0];
|
||
|
UINT16 xx;
|
||
|
|
||
|
L2CAP_TRACE_DEBUG ("L2CAP - l2c_ucd_discover_cback");
|
||
|
|
||
|
for (xx = 0; xx < MAX_L2CAP_CLIENTS; xx++, p_rcb++)
|
||
|
{
|
||
|
if (p_rcb->in_use)
|
||
|
{
|
||
|
/* if this application is waiting UCD reception info */
|
||
|
if (( info_type == L2CAP_UCD_INFO_TYPE_RECEPTION )
|
||
|
&& ( p_rcb->ucd.state & L2C_UCD_STATE_W4_RECEPTION ))
|
||
|
{
|
||
|
p_rcb->ucd.cb_info.pL2CA_UCD_Discover_Cb (rem_bda, info_type, data);
|
||
|
p_rcb->ucd.state &= ~(L2C_UCD_STATE_W4_RECEPTION);
|
||
|
}
|
||
|
|
||
|
/* if this application is waiting UCD MTU info */
|
||
|
if (( info_type == L2CAP_UCD_INFO_TYPE_MTU )
|
||
|
&& ( p_rcb->ucd.state & L2C_UCD_STATE_W4_MTU ))
|
||
|
{
|
||
|
p_rcb->ucd.cb_info.pL2CA_UCD_Discover_Cb (rem_bda, info_type, data);
|
||
|
p_rcb->ucd.state &= ~(L2C_UCD_STATE_W4_MTU);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*******************************************************************************
|
||
|
**
|
||
|
** Function l2c_ucd_data_ind_cback
|
||
|
**
|
||
|
** Description UCD Data callback
|
||
|
**
|
||
|
** Returns void
|
||
|
**
|
||
|
*******************************************************************************/
|
||
|
static void l2c_ucd_data_ind_cback (BD_ADDR rem_bda, BT_HDR *p_buf)
|
||
|
{
|
||
|
UINT8 *p;
|
||
|
UINT16 psm;
|
||
|
tL2C_RCB *p_rcb;
|
||
|
|
||
|
L2CAP_TRACE_DEBUG ("L2CAP - l2c_ucd_data_ind_cback");
|
||
|
|
||
|
p = (UINT8 *)(p_buf + 1) + p_buf->offset;
|
||
|
STREAM_TO_UINT16(psm, p)
|
||
|
|
||
|
p_buf->offset += L2CAP_UCD_OVERHEAD;
|
||
|
p_buf->len -= L2CAP_UCD_OVERHEAD;
|
||
|
|
||
|
if ((p_rcb = l2cu_find_rcb_by_psm (psm)) == NULL)
|
||
|
{
|
||
|
L2CAP_TRACE_ERROR ("L2CAP - no RCB for l2c_ucd_data_ind_cback, PSM: 0x%04x", psm);
|
||
|
GKI_freebuf (p_buf);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
p_rcb->ucd.cb_info.pL2CA_UCD_Data_Cb(rem_bda, p_buf);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*******************************************************************************
|
||
|
**
|
||
|
** Function l2c_ucd_congestion_status_cback
|
||
|
**
|
||
|
** Description UCD Congestion Status callback
|
||
|
**
|
||
|
** Returns void
|
||
|
**
|
||
|
*******************************************************************************/
|
||
|
static void l2c_ucd_congestion_status_cback (BD_ADDR rem_bda, BOOLEAN is_congested)
|
||
|
{
|
||
|
tL2C_RCB *p_rcb = &l2cb.rcb_pool[0];
|
||
|
UINT16 xx;
|
||
|
|
||
|
L2CAP_TRACE_DEBUG ("L2CAP - l2c_ucd_congestion_status_cback");
|
||
|
|
||
|
for (xx = 0; xx < MAX_L2CAP_CLIENTS; xx++, p_rcb++)
|
||
|
{
|
||
|
if (( p_rcb->in_use )
|
||
|
&&( p_rcb->ucd.state != L2C_UCD_STATE_UNUSED ))
|
||
|
{
|
||
|
if ( p_rcb->ucd.cb_info.pL2CA_UCD_Congestion_Status_Cb )
|
||
|
{
|
||
|
L2CAP_TRACE_DEBUG ("L2CAP - Calling UCDCongestionStatus_Cb (%d), PSM=0x%04x, BDA: %08x%04x,",
|
||
|
is_congested, p_rcb->psm,
|
||
|
(rem_bda[0]<<24)+(rem_bda[1]<<16)+(rem_bda[2]<<8)+rem_bda[3],
|
||
|
(rem_bda[4]<<8)+rem_bda[5]);
|
||
|
|
||
|
p_rcb->ucd.cb_info.pL2CA_UCD_Congestion_Status_Cb ( rem_bda, is_congested );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*******************************************************************************
|
||
|
**
|
||
|
** Function l2c_ucd_disconnect_ind_cback
|
||
|
**
|
||
|
** Description UCD disconnect callback (This prevent to access null pointer)
|
||
|
**
|
||
|
** Returns void
|
||
|
**
|
||
|
*******************************************************************************/
|
||
|
static void l2c_ucd_disconnect_ind_cback (UINT16 cid, BOOLEAN result)
|
||
|
{
|
||
|
/* do nothing */
|
||
|
}
|
||
|
|
||
|
/*******************************************************************************
|
||
|
**
|
||
|
** Function l2c_ucd_config_ind_cback
|
||
|
**
|
||
|
** Description UCD config callback (This prevent to access null pointer)
|
||
|
**
|
||
|
** Returns void
|
||
|
**
|
||
|
*******************************************************************************/
|
||
|
static void l2c_ucd_config_ind_cback (UINT16 cid, tL2CAP_CFG_INFO *p_cfg)
|
||
|
{
|
||
|
/* do nothing */
|
||
|
}
|
||
|
|
||
|
/*******************************************************************************
|
||
|
**
|
||
|
** Function l2c_ucd_config_cfm_cback
|
||
|
**
|
||
|
** Description UCD config callback (This prevent to access null pointer)
|
||
|
**
|
||
|
** Returns void
|
||
|
**
|
||
|
*******************************************************************************/
|
||
|
static void l2c_ucd_config_cfm_cback (UINT16 cid, tL2CAP_CFG_INFO *p_cfg)
|
||
|
{
|
||
|
/* do nothing */
|
||
|
}
|
||
|
|
||
|
/*******************************************************************************
|
||
|
**
|
||
|
** Function L2CA_UcdRegister
|
||
|
**
|
||
|
** Description Register PSM on UCD.
|
||
|
**
|
||
|
** Parameters: tL2CAP_UCD_CB_INFO
|
||
|
**
|
||
|
** Return value: TRUE if successs
|
||
|
**
|
||
|
*******************************************************************************/
|
||
|
BOOLEAN L2CA_UcdRegister ( UINT16 psm, tL2CAP_UCD_CB_INFO *p_cb_info )
|
||
|
{
|
||
|
tL2C_RCB *p_rcb;
|
||
|
|
||
|
L2CAP_TRACE_API ("L2CA_UcdRegister() PSM: 0x%04x", psm);
|
||
|
|
||
|
if ((!p_cb_info->pL2CA_UCD_Discover_Cb)
|
||
|
|| (!p_cb_info->pL2CA_UCD_Data_Cb))
|
||
|
{
|
||
|
L2CAP_TRACE_ERROR ("L2CAP - no callback registering PSM(0x%04x) on UCD", psm);
|
||
|
return (FALSE);
|
||
|
}
|
||
|
|
||
|
if ((p_rcb = l2cu_find_rcb_by_psm (psm)) == NULL)
|
||
|
{
|
||
|
L2CAP_TRACE_ERROR ("L2CAP - no RCB for L2CA_UcdRegister, PSM: 0x%04x", psm);
|
||
|
return (FALSE);
|
||
|
}
|
||
|
|
||
|
p_rcb->ucd.state = L2C_UCD_STATE_W4_DATA;
|
||
|
p_rcb->ucd.cb_info = *p_cb_info;
|
||
|
|
||
|
/* check if master rcb is created for UCD */
|
||
|
if ((p_rcb = l2cu_find_rcb_by_psm (L2C_UCD_RCB_ID)) == NULL)
|
||
|
{
|
||
|
if ((p_rcb = l2cu_allocate_rcb (L2C_UCD_RCB_ID)) == NULL)
|
||
|
{
|
||
|
L2CAP_TRACE_ERROR ("L2CAP - no RCB available for L2CA_UcdRegister");
|
||
|
return (FALSE);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* these callback functions will forward data to each UCD application */
|
||
|
p_rcb->ucd.cb_info.pL2CA_UCD_Discover_Cb = l2c_ucd_discover_cback;
|
||
|
p_rcb->ucd.cb_info.pL2CA_UCD_Data_Cb = l2c_ucd_data_ind_cback;
|
||
|
p_rcb->ucd.cb_info.pL2CA_UCD_Congestion_Status_Cb = l2c_ucd_congestion_status_cback;
|
||
|
|
||
|
memset (&p_rcb->api, 0, sizeof(tL2CAP_APPL_INFO));
|
||
|
p_rcb->api.pL2CA_DisconnectInd_Cb = l2c_ucd_disconnect_ind_cback;
|
||
|
|
||
|
/* This will make L2CAP check UCD congestion callback */
|
||
|
p_rcb->api.pL2CA_CongestionStatus_Cb = NULL;
|
||
|
|
||
|
/* do nothing but prevent crash */
|
||
|
p_rcb->api.pL2CA_ConfigInd_Cb = l2c_ucd_config_ind_cback;
|
||
|
p_rcb->api.pL2CA_ConfigCfm_Cb = l2c_ucd_config_cfm_cback;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return (TRUE);
|
||
|
}
|
||
|
|
||
|
/*******************************************************************************
|
||
|
**
|
||
|
** Function L2CA_UcdDeregister
|
||
|
**
|
||
|
** Description Deregister PSM on UCD.
|
||
|
**
|
||
|
** Parameters: PSM
|
||
|
**
|
||
|
** Return value: TRUE if successs
|
||
|
**
|
||
|
*******************************************************************************/
|
||
|
BOOLEAN L2CA_UcdDeregister ( UINT16 psm )
|
||
|
{
|
||
|
tL2C_CCB *p_ccb;
|
||
|
tL2C_RCB *p_rcb;
|
||
|
UINT16 xx;
|
||
|
|
||
|
L2CAP_TRACE_API ("L2CA_UcdDeregister() PSM: 0x%04x", psm);
|
||
|
|
||
|
if ((p_rcb = l2cu_find_rcb_by_psm (psm)) == NULL)
|
||
|
{
|
||
|
L2CAP_TRACE_ERROR ("L2CAP - no RCB for L2CA_UcdDeregister, PSM: 0x%04x", psm);
|
||
|
return (FALSE);
|
||
|
}
|
||
|
|
||
|
p_rcb->ucd.state = L2C_UCD_STATE_UNUSED;
|
||
|
|
||
|
/* check this was the last UCD registration */
|
||
|
p_rcb = &l2cb.rcb_pool[0];
|
||
|
|
||
|
for (xx = 0; xx < MAX_L2CAP_CLIENTS; xx++, p_rcb++)
|
||
|
{
|
||
|
if ((p_rcb->in_use) && (p_rcb->ucd.state != L2C_UCD_STATE_UNUSED))
|
||
|
return (TRUE);
|
||
|
}
|
||
|
|
||
|
/* delete master rcb for UCD */
|
||
|
if ((p_rcb = l2cu_find_rcb_by_psm (L2C_UCD_RCB_ID)) != NULL)
|
||
|
{
|
||
|
l2cu_release_rcb (p_rcb);
|
||
|
}
|
||
|
|
||
|
/* delete CCB for UCD */
|
||
|
p_ccb = l2cb.ccb_pool;
|
||
|
for ( xx = 0; xx < MAX_L2CAP_CHANNELS; xx++ )
|
||
|
{
|
||
|
if (( p_ccb->in_use )
|
||
|
&&( p_ccb->local_cid == L2CAP_CONNECTIONLESS_CID ))
|
||
|
{
|
||
|
l2cu_release_ccb (p_ccb);
|
||
|
}
|
||
|
p_ccb++;
|
||
|
}
|
||
|
|
||
|
return (TRUE);
|
||
|
}
|
||
|
|
||
|
/*******************************************************************************
|
||
|
**
|
||
|
** 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_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);
|
||
|
GKI_freebuf (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 )
|
||
|
{
|
||
|
GKI_freebuf (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))
|
||
|
{
|
||
|
GKI_freebuf (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);
|
||
|
GKI_freebuf (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,
|
||
|
(p_ccb->xmit_hold_q.count + p_lcb->ucd_out_sec_pending_q.count),
|
||
|
p_ccb->buff_quota);
|
||
|
|
||
|
GKI_freebuf (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 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_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 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 l2c_ucd_delete_sec_pending_q
|
||
|
**
|
||
|
** Description discard all of UCD packets in security pending queue
|
||
|
**
|
||
|
** Returns None
|
||
|
**
|
||
|
*******************************************************************************/
|
||
|
void l2c_ucd_delete_sec_pending_q(tL2C_LCB *p_lcb)
|
||
|
{
|
||
|
/* clean up any security pending UCD */
|
||
|
while (p_lcb->ucd_out_sec_pending_q.p_first)
|
||
|
GKI_freebuf (GKI_dequeue (&p_lcb->ucd_out_sec_pending_q));
|
||
|
|
||
|
while (p_lcb->ucd_in_sec_pending_q.p_first)
|
||
|
GKI_freebuf (GKI_dequeue (&p_lcb->ucd_in_sec_pending_q));
|
||
|
}
|
||
|
|
||
|
/*******************************************************************************
|
||
|
**
|
||
|
** Function l2c_ucd_check_pending_info_req
|
||
|
**
|
||
|
** Description check if any application is waiting for UCD information
|
||
|
**
|
||
|
** Return TRUE if any pending UCD info request
|
||
|
**
|
||
|
*******************************************************************************/
|
||
|
BOOLEAN l2c_ucd_check_pending_info_req(tL2C_CCB *p_ccb)
|
||
|
{
|
||
|
tL2C_RCB *p_rcb = &l2cb.rcb_pool[0];
|
||
|
UINT16 xx;
|
||
|
BOOLEAN pending = FALSE;
|
||
|
|
||
|
if (p_ccb == NULL)
|
||
|
{
|
||
|
L2CAP_TRACE_ERROR ("L2CAP - NULL p_ccb in l2c_ucd_check_pending_info_req");
|
||
|
return (FALSE);
|
||
|
}
|
||
|
|
||
|
for (xx = 0; xx < MAX_L2CAP_CLIENTS; xx++, p_rcb++)
|
||
|
{
|
||
|
if (p_rcb->in_use)
|
||
|
{
|
||
|
/* if application is waiting UCD reception info */
|
||
|
if (p_rcb->ucd.state & L2C_UCD_STATE_W4_RECEPTION)
|
||
|
{
|
||
|
/* if this information is available */
|
||
|
if ( p_ccb->p_lcb->info_rx_bits & (1 << L2CAP_EXTENDED_FEATURES_INFO_TYPE) )
|
||
|
{
|
||
|
if (!(p_ccb->p_lcb->peer_ext_fea & L2CAP_EXTFEA_UCD_RECEPTION))
|
||
|
{
|
||
|
L2CAP_TRACE_WARNING ("L2CAP - UCD is not supported by peer, l2c_ucd_check_pending_info_req");
|
||
|
|
||
|
l2c_ucd_delete_sec_pending_q(p_ccb->p_lcb);
|
||
|
l2cu_release_ccb (p_ccb);
|
||
|
}
|
||
|
|
||
|
p_ccb->p_rcb->ucd.cb_info.pL2CA_UCD_Discover_Cb (p_ccb->p_lcb->remote_bd_addr,
|
||
|
L2CAP_UCD_INFO_TYPE_RECEPTION,
|
||
|
p_ccb->p_lcb->peer_ext_fea & L2CAP_EXTFEA_UCD_RECEPTION);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pending = TRUE;
|
||
|
if (p_ccb->p_lcb->w4_info_rsp == FALSE)
|
||
|
{
|
||
|
l2cu_send_peer_info_req (p_ccb->p_lcb, L2CAP_EXTENDED_FEATURES_INFO_TYPE);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* if application is waiting for UCD MTU */
|
||
|
if (p_rcb->ucd.state & L2C_UCD_STATE_W4_MTU)
|
||
|
{
|
||
|
/* if this information is available */
|
||
|
if ( p_ccb->p_lcb->info_rx_bits & (1 << L2CAP_CONNLESS_MTU_INFO_TYPE))
|
||
|
{
|
||
|
p_ccb->p_rcb->ucd.cb_info.pL2CA_UCD_Discover_Cb (p_ccb->p_lcb->remote_bd_addr,
|
||
|
L2CAP_UCD_INFO_TYPE_MTU,
|
||
|
p_ccb->p_lcb->ucd_mtu);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pending = TRUE;
|
||
|
if (p_ccb->p_lcb->w4_info_rsp == FALSE)
|
||
|
{
|
||
|
l2cu_send_peer_info_req (p_ccb->p_lcb, L2CAP_CONNLESS_MTU_INFO_TYPE);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return (pending);
|
||
|
}
|
||
|
|
||
|
/*******************************************************************************
|
||
|
**
|
||
|
** Function l2c_ucd_enqueue_pending_out_sec_q
|
||
|
**
|
||
|
** Description enqueue outgoing UCD packet into security pending queue
|
||
|
** and check congestion
|
||
|
**
|
||
|
** Return None
|
||
|
**
|
||
|
*******************************************************************************/
|
||
|
void l2c_ucd_enqueue_pending_out_sec_q(tL2C_CCB *p_ccb, void *p_data)
|
||
|
{
|
||
|
GKI_enqueue (&p_ccb->p_lcb->ucd_out_sec_pending_q, p_data);
|
||
|
l2cu_check_channel_congestion (p_ccb);
|
||
|
}
|
||
|
|
||
|
/*******************************************************************************
|
||
|
**
|
||
|
** Function l2c_ucd_check_pending_out_sec_q
|
||
|
**
|
||
|
** Description check outgoing security
|
||
|
**
|
||
|
** Return TRUE if any UCD packet for security
|
||
|
**
|
||
|
*******************************************************************************/
|
||
|
BOOLEAN l2c_ucd_check_pending_out_sec_q(tL2C_CCB *p_ccb)
|
||
|
{
|
||
|
UINT8 *p;
|
||
|
UINT16 psm;
|
||
|
BT_HDR *p_buf;
|
||
|
|
||
|
if ( p_ccb->p_lcb->ucd_out_sec_pending_q.count )
|
||
|
{
|
||
|
p_buf = (BT_HDR*)(p_ccb->p_lcb->ucd_out_sec_pending_q.p_first);
|
||
|
p = (UINT8 *)(p_buf + 1) + p_buf->offset;
|
||
|
STREAM_TO_UINT16(psm, p)
|
||
|
|
||
|
p_ccb->chnl_state = CST_ORIG_W4_SEC_COMP;
|
||
|
btm_sec_l2cap_access_req (p_ccb->p_lcb->remote_bd_addr, psm,
|
||
|
p_ccb->p_lcb->handle, CONNLESS_ORIG, &l2c_link_sec_comp, p_ccb);
|
||
|
|
||
|
return (TRUE);
|
||
|
}
|
||
|
return (FALSE);
|
||
|
}
|
||
|
|
||
|
/*******************************************************************************
|
||
|
**
|
||
|
** Function l2c_ucd_send_pending_out_sec_q
|
||
|
**
|
||
|
** Description dequeue UCD packet from security pending queue and
|
||
|
** enqueue it into CCB
|
||
|
**
|
||
|
** Return None
|
||
|
**
|
||
|
*******************************************************************************/
|
||
|
void l2c_ucd_send_pending_out_sec_q(tL2C_CCB *p_ccb)
|
||
|
{
|
||
|
BT_HDR *p_buf;
|
||
|
|
||
|
if ( p_ccb->p_lcb->ucd_out_sec_pending_q.count )
|
||
|
{
|
||
|
p_buf = (BT_HDR*)GKI_dequeue (&p_ccb->p_lcb->ucd_out_sec_pending_q);
|
||
|
|
||
|
l2c_enqueue_peer_data (p_ccb, (BT_HDR *)p_buf);
|
||
|
l2c_link_check_send_pkts (p_ccb->p_lcb, NULL, NULL);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*******************************************************************************
|
||
|
**
|
||
|
** Function l2c_ucd_discard_pending_out_sec_q
|
||
|
**
|
||
|
** Description dequeue UCD packet from security pending queue and
|
||
|
** discard it.
|
||
|
**
|
||
|
** Return None
|
||
|
**
|
||
|
*******************************************************************************/
|
||
|
void l2c_ucd_discard_pending_out_sec_q(tL2C_CCB *p_ccb)
|
||
|
{
|
||
|
BT_HDR *p_buf;
|
||
|
|
||
|
p_buf = (BT_HDR*)GKI_dequeue (&p_ccb->p_lcb->ucd_out_sec_pending_q);
|
||
|
|
||
|
/* we may need to report to application */
|
||
|
|
||
|
if (p_buf)
|
||
|
{
|
||
|
GKI_freebuf (p_buf);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*******************************************************************************
|
||
|
**
|
||
|
** Function l2c_ucd_check_pending_in_sec_q
|
||
|
**
|
||
|
** Description check incoming security
|
||
|
**
|
||
|
** Return TRUE if any UCD packet for security
|
||
|
**
|
||
|
*******************************************************************************/
|
||
|
BOOLEAN l2c_ucd_check_pending_in_sec_q(tL2C_CCB *p_ccb)
|
||
|
{
|
||
|
UINT8 *p;
|
||
|
UINT16 psm;
|
||
|
BT_HDR *p_buf;
|
||
|
|
||
|
if ( p_ccb->p_lcb->ucd_in_sec_pending_q.count )
|
||
|
{
|
||
|
p_buf = (BT_HDR*)(p_ccb->p_lcb->ucd_in_sec_pending_q.p_first);
|
||
|
p = (UINT8 *)(p_buf + 1) + p_buf->offset;
|
||
|
STREAM_TO_UINT16(psm, p)
|
||
|
|
||
|
p_ccb->chnl_state = CST_TERM_W4_SEC_COMP;
|
||
|
btm_sec_l2cap_access_req (p_ccb->p_lcb->remote_bd_addr, psm,
|
||
|
p_ccb->p_lcb->handle, CONNLESS_TERM, &l2c_link_sec_comp, p_ccb);
|
||
|
|
||
|
return (TRUE);
|
||
|
}
|
||
|
return (FALSE);
|
||
|
}
|
||
|
|
||
|
/*******************************************************************************
|
||
|
**
|
||
|
** Function l2c_ucd_send_pending_in_sec_q
|
||
|
**
|
||
|
** Description dequeue UCD packet from security pending queue and
|
||
|
** send it to application
|
||
|
**
|
||
|
** Return None
|
||
|
**
|
||
|
*******************************************************************************/
|
||
|
void l2c_ucd_send_pending_in_sec_q(tL2C_CCB *p_ccb)
|
||
|
{
|
||
|
BT_HDR *p_buf;
|
||
|
|
||
|
if ( p_ccb->p_lcb->ucd_in_sec_pending_q.count )
|
||
|
{
|
||
|
p_buf = (BT_HDR*)GKI_dequeue (&p_ccb->p_lcb->ucd_in_sec_pending_q);
|
||
|
|
||
|
p_ccb->p_rcb->ucd.cb_info.pL2CA_UCD_Data_Cb(p_ccb->p_lcb->remote_bd_addr, (BT_HDR *)p_buf);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*******************************************************************************
|
||
|
**
|
||
|
** Function l2c_ucd_discard_pending_in_sec_q
|
||
|
**
|
||
|
** Description dequeue UCD packet from security pending queue and
|
||
|
** discard it.
|
||
|
**
|
||
|
** Return None
|
||
|
**
|
||
|
*******************************************************************************/
|
||
|
void l2c_ucd_discard_pending_in_sec_q(tL2C_CCB *p_ccb)
|
||
|
{
|
||
|
BT_HDR *p_buf;
|
||
|
|
||
|
p_buf = (BT_HDR*)GKI_dequeue (&p_ccb->p_lcb->ucd_in_sec_pending_q);
|
||
|
|
||
|
if (p_buf)
|
||
|
{
|
||
|
GKI_freebuf (p_buf);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*******************************************************************************
|
||
|
**
|
||
|
** Function l2c_ucd_check_rx_pkts
|
||
|
**
|
||
|
** Description Check if UCD reception is registered.
|
||
|
** Process received UCD packet if application is expecting.
|
||
|
**
|
||
|
** Return TRUE if UCD reception is registered
|
||
|
**
|
||
|
*******************************************************************************/
|
||
|
BOOLEAN l2c_ucd_check_rx_pkts(tL2C_LCB *p_lcb, BT_HDR *p_msg)
|
||
|
{
|
||
|
tL2C_CCB *p_ccb;
|
||
|
tL2C_RCB *p_rcb;
|
||
|
|
||
|
if (((p_ccb = l2cu_find_ccb_by_cid (p_lcb, L2CAP_CONNECTIONLESS_CID)) != NULL)
|
||
|
||((p_rcb = l2cu_find_rcb_by_psm (L2C_UCD_RCB_ID)) != NULL))
|
||
|
{
|
||
|
if (p_ccb == NULL)
|
||
|
{
|
||
|
/* Allocate a channel control block */
|
||
|
if ((p_ccb = l2cu_allocate_ccb (p_lcb, 0)) == NULL)
|
||
|
{
|
||
|
L2CAP_TRACE_WARNING ("L2CAP - no CCB for UCD reception");
|
||
|
GKI_freebuf (p_msg);
|
||
|
return TRUE;
|
||
|
}
|
||
|
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);
|
||
|
|
||
|
/* Save registration info */
|
||
|
p_ccb->p_rcb = p_rcb;
|
||
|
|
||
|
p_ccb->chnl_state = CST_OPEN;
|
||
|
}
|
||
|
}
|
||
|
l2c_csm_execute(p_ccb, L2CEVT_L2CAP_DATA, p_msg);
|
||
|
return TRUE;
|
||
|
}
|
||
|
else
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
/*******************************************************************************
|
||
|
**
|
||
|
** Function l2c_ucd_process_event
|
||
|
**
|
||
|
** Description This is called from main state machine when LCID is connectionless
|
||
|
** Process the event if it is for UCD.
|
||
|
**
|
||
|
** Return TRUE if the event is consumed by UCD
|
||
|
** FALSE if the event needs to be processed by main state machine
|
||
|
**
|
||
|
*******************************************************************************/
|
||
|
BOOLEAN l2c_ucd_process_event(tL2C_CCB *p_ccb, UINT16 event, void *p_data)
|
||
|
{
|
||
|
/* if the event is not processed by this function, this variable will be set to FALSE */
|
||
|
BOOLEAN done = TRUE;
|
||
|
|
||
|
switch (p_ccb->chnl_state)
|
||
|
{
|
||
|
case CST_CLOSED:
|
||
|
switch (event)
|
||
|
{
|
||
|
case L2CEVT_LP_CONNECT_CFM: /* Link came up */
|
||
|
/* check if waiting for UCD info */
|
||
|
if (!l2c_ucd_check_pending_info_req (p_ccb))
|
||
|
{
|
||
|
/* check if any outgoing UCD packet is waiting security check */
|
||
|
if (!l2c_ucd_check_pending_out_sec_q(p_ccb))
|
||
|
{
|
||
|
p_ccb->chnl_state = CST_OPEN;
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case L2CEVT_L2CAP_DATA: /* Peer data packet rcvd */
|
||
|
GKI_enqueue (&p_ccb->p_lcb->ucd_in_sec_pending_q, p_data);
|
||
|
break;
|
||
|
|
||
|
case L2CEVT_L2CA_DATA_WRITE: /* Upper layer data to send */
|
||
|
l2c_ucd_enqueue_pending_out_sec_q(p_ccb, p_data);
|
||
|
break;
|
||
|
|
||
|
case L2CEVT_L2CAP_INFO_RSP:
|
||
|
/* check if waiting for UCD info */
|
||
|
if (!l2c_ucd_check_pending_info_req (p_ccb))
|
||
|
{
|
||
|
/* check if any outgoing UCD packet is waiting security check */
|
||
|
if (!l2c_ucd_check_pending_out_sec_q(p_ccb))
|
||
|
{
|
||
|
p_ccb->chnl_state = CST_OPEN;
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
done = FALSE; /* main state machine continues to process event */
|
||
|
break;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case CST_ORIG_W4_SEC_COMP:
|
||
|
switch (event)
|
||
|
{
|
||
|
case L2CEVT_SEC_RE_SEND_CMD: /* BTM has enough info to proceed */
|
||
|
/* check if any outgoing UCD packet is waiting security check */
|
||
|
if (!l2c_ucd_check_pending_out_sec_q(p_ccb))
|
||
|
{
|
||
|
p_ccb->chnl_state = CST_OPEN;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case L2CEVT_SEC_COMP: /* Security completed success */
|
||
|
p_ccb->chnl_state = CST_OPEN;
|
||
|
l2c_ucd_send_pending_out_sec_q(p_ccb);
|
||
|
|
||
|
if ( p_ccb->p_lcb->ucd_out_sec_pending_q.count )
|
||
|
{
|
||
|
/* start a timer to send next UCD packet in OPEN state */
|
||
|
/* it will prevent stack overflow */
|
||
|
btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_L2CAP_CHNL, 0);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* start a timer for idle timeout of UCD */
|
||
|
btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_L2CAP_CHNL, p_ccb->fixed_chnl_idle_tout);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case L2CEVT_SEC_COMP_NEG:
|
||
|
p_ccb->chnl_state = CST_OPEN;
|
||
|
l2c_ucd_discard_pending_out_sec_q(p_ccb);
|
||
|
|
||
|
/* start a timer for idle timeout of UCD */
|
||
|
btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_L2CAP_CHNL, p_ccb->fixed_chnl_idle_tout);
|
||
|
break;
|
||
|
|
||
|
case L2CEVT_L2CA_DATA_WRITE: /* Upper layer data to send */
|
||
|
l2c_ucd_enqueue_pending_out_sec_q(p_ccb, p_data);
|
||
|
break;
|
||
|
|
||
|
case L2CEVT_L2CAP_DATA: /* Peer data packet rcvd */
|
||
|
GKI_enqueue (&p_ccb->p_lcb->ucd_in_sec_pending_q, p_data);
|
||
|
break;
|
||
|
|
||
|
case L2CEVT_L2CAP_INFO_RSP:
|
||
|
/* check if waiting for UCD info */
|
||
|
l2c_ucd_check_pending_info_req (p_ccb);
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
done = FALSE; /* main state machine continues to process event */
|
||
|
break;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
|
||
|
case CST_TERM_W4_SEC_COMP:
|
||
|
switch (event)
|
||
|
{
|
||
|
case L2CEVT_SEC_COMP:
|
||
|
p_ccb->chnl_state = CST_OPEN;
|
||
|
l2c_ucd_send_pending_in_sec_q (p_ccb);
|
||
|
|
||
|
if ( p_ccb->p_lcb->ucd_in_sec_pending_q.count )
|
||
|
{
|
||
|
/* start a timer to check next UCD packet in OPEN state */
|
||
|
/* it will prevent stack overflow */
|
||
|
btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_L2CAP_CHNL, 0);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* start a timer for idle timeout of UCD */
|
||
|
btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_L2CAP_CHNL, p_ccb->fixed_chnl_idle_tout);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case L2CEVT_SEC_COMP_NEG:
|
||
|
if (((tL2C_CONN_INFO *)p_data)->status == BTM_DELAY_CHECK)
|
||
|
{
|
||
|
done = FALSE;
|
||
|
break;
|
||
|
}
|
||
|
p_ccb->chnl_state = CST_OPEN;
|
||
|
l2c_ucd_discard_pending_in_sec_q (p_ccb);
|
||
|
|
||
|
/* start a timer for idle timeout of UCD */
|
||
|
btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_L2CAP_CHNL, p_ccb->fixed_chnl_idle_tout);
|
||
|
break;
|
||
|
|
||
|
case L2CEVT_L2CA_DATA_WRITE: /* Upper layer data to send */
|
||
|
l2c_ucd_enqueue_pending_out_sec_q(p_ccb, p_data);
|
||
|
break;
|
||
|
|
||
|
case L2CEVT_L2CAP_DATA: /* Peer data packet rcvd */
|
||
|
GKI_enqueue (&p_ccb->p_lcb->ucd_in_sec_pending_q, p_data);
|
||
|
break;
|
||
|
|
||
|
case L2CEVT_SEC_RE_SEND_CMD: /* BTM has enough info to proceed */
|
||
|
/* check if any incoming UCD packet is waiting security check */
|
||
|
if (!l2c_ucd_check_pending_in_sec_q(p_ccb))
|
||
|
{
|
||
|
p_ccb->chnl_state = CST_OPEN;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case L2CEVT_L2CAP_INFO_RSP:
|
||
|
/* check if waiting for UCD info */
|
||
|
l2c_ucd_check_pending_info_req (p_ccb);
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
done = FALSE; /* main state machine continues to process event */
|
||
|
break;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case CST_OPEN:
|
||
|
switch (event)
|
||
|
{
|
||
|
case L2CEVT_L2CAP_DATA: /* Peer data packet rcvd */
|
||
|
/* stop idle timer of UCD */
|
||
|
btu_stop_timer (&p_ccb->timer_entry);
|
||
|
|
||
|
GKI_enqueue (&p_ccb->p_lcb->ucd_in_sec_pending_q, p_data);
|
||
|
l2c_ucd_check_pending_in_sec_q (p_ccb);
|
||
|
break;
|
||
|
|
||
|
case L2CEVT_L2CA_DATA_WRITE: /* Upper layer data to send */
|
||
|
/* stop idle timer of UCD */
|
||
|
btu_stop_timer (&p_ccb->timer_entry);
|
||
|
|
||
|
l2c_ucd_enqueue_pending_out_sec_q(p_ccb, p_data);
|
||
|
|
||
|
/* coverity[check_return] */ /* coverity[unchecked_value] */
|
||
|
/* success changes state, failure stays in current state */
|
||
|
l2c_ucd_check_pending_out_sec_q (p_ccb);
|
||
|
break;
|
||
|
|
||
|
case L2CEVT_TIMEOUT:
|
||
|
/* check if any UCD packet is waiting security check */
|
||
|
if ((!l2c_ucd_check_pending_in_sec_q(p_ccb))
|
||
|
&&(!l2c_ucd_check_pending_out_sec_q(p_ccb)))
|
||
|
{
|
||
|
l2cu_release_ccb (p_ccb);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case L2CEVT_L2CAP_INFO_RSP:
|
||
|
/* check if waiting for UCD info */
|
||
|
l2c_ucd_check_pending_info_req (p_ccb);
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
done = FALSE; /* main state machine continues to process event */
|
||
|
break;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
done = FALSE; /* main state machine continues to process event */
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
return done;
|
||
|
}
|
||
|
#endif /* (L2CAP_UCD_INCLUDED == TRUE) */
|