mirror of
				https://github.com/espressif/esp-idf.git
				synced 2025-10-31 15:11:40 +01:00 
			
		
		
		
	1. add the L1 include path with a prefix, such like osi/list.h, stack/a2d_api.h and etc. 2. modify component, only bluedroid/api/include/api is export to another component and application, other include path just for bluedroid used 3. put bluedroid/include into common/include/common, so the root directory of bluedroid have no include path. 4. modify doxygen to use esp_bt.h and redirect to component/bt/bluedroid/api/include/api/ fix compile
		
			
				
	
	
		
			1078 lines
		
	
	
		
			37 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1078 lines
		
	
	
		
			37 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 "stack/bt_types.h"
 | |
| #include "stack/hcidefs.h"
 | |
| #include "stack/hcimsgs.h"
 | |
| #include "stack/l2cdefs.h"
 | |
| #include "l2c_int.h"
 | |
| #include "stack/btu.h"
 | |
| #include "stack/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);
 | |
|         osi_free (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);
 | |
|         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        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) {
 | |
|         osi_free(fixed_queue_try_dequeue(p_lcb->ucd_out_sec_pending_q));
 | |
| 	}
 | |
|     fixed_queue_free(p_lcb->ucd_out_sec_pending_q, NULL);
 | |
|     p_lcb->ucd_out_sec_pending_q = NULL;
 | |
| 
 | |
|     while (! fixed_queue_is_empty(p_lcb->ucd_in_sec_pending_q)) {
 | |
|         osi_free(fixed_queue_try_dequeue(p_lcb->ucd_in_sec_pending_q));
 | |
| 	}
 | |
|     fixed_queue_free(p_lcb->ucd_in_sec_pending_q);
 | |
|     p_lcb->ucd_in_sec_pending_q = NULL;
 | |
| }
 | |
| 
 | |
| /*******************************************************************************
 | |
| **
 | |
| **  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)
 | |
| {
 | |
|     fixed_queue_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)
 | |
| {
 | |
|     BT_HDR *p_buf = (BT_HDR*)fixed_queue_try_peek_first(p_ccb->p_lcb->ucd_out_sec_pending_q);
 | |
| 
 | |
|     if (p_buf != NULL) {
 | |
|         UINT16 psm;
 | |
|         UINT8 *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 = (BT_HDR*)fixed_queue_try_dequeue(p_ccb->p_lcb->ucd_out_sec_pending_q);
 | |
| 
 | |
|     if (p_buf != NULL) {
 | |
|         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 = (BT_HDR*)fixed_queue_try_dequeue(p_ccb->p_lcb->ucd_out_sec_pending_q);
 | |
| 
 | |
|     /* we may need to report to application */
 | |
| 
 | |
|     if (p_buf) {
 | |
|         osi_free (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)
 | |
| {
 | |
|     BT_HDR *p_buf = (BT_HDR*)fixed_queue_try_dequeue(p_ccb->p_lcb->ucd_in_sec_pending_q);
 | |
| 
 | |
|     if (p_buf != NULL) {
 | |
|         UINT16 psm;
 | |
|         UINT8 *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 = (BT_HDR*)fixed_queue_try_dequeue(p_ccb->p_lcb->ucd_in_sec_pending_q)
 | |
| 
 | |
|     if (p_buf != NULL) {
 | |
|         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 = (BT_HDR*)fixed_queue_try_dequeue(p_ccb->p_lcb->ucd_in_sec_pending_q);
 | |
| 
 | |
|     if (p_buf) {
 | |
|         osi_free (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");
 | |
|                 osi_free (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    */
 | |
|             fixed_queue_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 (! fixed_queue_is_empty(p_ccb->p_lcb->ucd_out_sec_pending_q))
 | |
|             {
 | |
|                 /* 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    */
 | |
|             fixed_queue_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 (! fixed_queue_is_empty(p_ccb->p_lcb->ucd_in_sec_pending_q)) {
 | |
|                 /* 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    */
 | |
|             fixed_queue_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);
 | |
| 
 | |
|             fixed_queue_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) */
 |