Fork ESP-IDF's bluetooth component
i want better sbc encoding, and no cla will stop me
This commit is contained in:
@@ -0,0 +1,444 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* Copyright (C) 2003-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 module contains API of the audio/video control transport protocol.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
#include <string.h>
|
||||
#include "stack/bt_types.h"
|
||||
#include "common/bt_target.h"
|
||||
#include "common/bt_defs.h"
|
||||
#include "stack/l2c_api.h"
|
||||
#include "stack/l2cdefs.h"
|
||||
#include "stack/btm_api.h"
|
||||
#include "stack/avct_api.h"
|
||||
#include "avct_int.h"
|
||||
#include "osi/allocator.h"
|
||||
|
||||
#if (defined(AVCT_INCLUDED) && AVCT_INCLUDED == TRUE)
|
||||
|
||||
/* Control block for AVCT */
|
||||
#if AVCT_DYNAMIC_MEMORY == FALSE
|
||||
tAVCT_CB avct_cb;
|
||||
#else
|
||||
tAVCT_CB *avct_cb_ptr;
|
||||
#endif
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function AVCT_Register
|
||||
**
|
||||
** Description This is the system level registration function for the
|
||||
** AVCTP protocol. This function initializes AVCTP and
|
||||
** prepares the protocol stack for its use. This function
|
||||
** must be called once by the system or platform using AVCTP
|
||||
** before the other functions of the API an be used.
|
||||
**
|
||||
**
|
||||
** Returns void
|
||||
**
|
||||
*******************************************************************************/
|
||||
void AVCT_Register(UINT16 mtu, UINT16 mtu_br, UINT8 sec_mask)
|
||||
{
|
||||
UNUSED(mtu_br);
|
||||
|
||||
AVCT_TRACE_API("AVCT_Register");
|
||||
|
||||
/* register PSM with L2CAP */
|
||||
L2CA_Register(AVCT_PSM, (tL2CAP_APPL_INFO *) &avct_l2c_appl);
|
||||
|
||||
/* set security level */
|
||||
BTM_SetSecurityLevel(TRUE, "", BTM_SEC_SERVICE_AVCTP, sec_mask, AVCT_PSM, 0, 0);
|
||||
BTM_SetSecurityLevel(FALSE, "", BTM_SEC_SERVICE_AVCTP, sec_mask, AVCT_PSM, 0, 0);
|
||||
|
||||
/* initialize AVCTP data structures */
|
||||
memset(&avct_cb, 0, sizeof(tAVCT_CB));
|
||||
|
||||
#if (AVCT_BROWSE_INCLUDED == TRUE)
|
||||
/* Include the browsing channel which uses eFCR */
|
||||
L2CA_Register(AVCT_BR_PSM, (tL2CAP_APPL_INFO *) &avct_l2c_br_appl);
|
||||
|
||||
BTM_SetSecurityLevel(TRUE, "", BTM_SEC_SERVICE_AVCTP_BROWSE, sec_mask, AVCT_BR_PSM, 0, 0);
|
||||
BTM_SetSecurityLevel(FALSE, "", BTM_SEC_SERVICE_AVCTP_BROWSE, sec_mask, AVCT_BR_PSM, 0, 0);
|
||||
|
||||
if (mtu_br < AVCT_MIN_BROWSE_MTU) {
|
||||
mtu_br = AVCT_MIN_BROWSE_MTU;
|
||||
}
|
||||
avct_cb.mtu_br = mtu_br;
|
||||
#endif
|
||||
|
||||
#if defined(AVCT_INITIAL_TRACE_LEVEL)
|
||||
avct_cb.trace_level = AVCT_INITIAL_TRACE_LEVEL;
|
||||
#else
|
||||
avct_cb.trace_level = BT_TRACE_LEVEL_NONE;
|
||||
#endif
|
||||
|
||||
if (mtu < AVCT_MIN_CONTROL_MTU) {
|
||||
mtu = AVCT_MIN_CONTROL_MTU;
|
||||
}
|
||||
/* store mtu */
|
||||
avct_cb.mtu = mtu;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function AVCT_Deregister
|
||||
**
|
||||
** Description This function is called to deregister use AVCTP protocol.
|
||||
** It is called when AVCTP is no longer being used by any
|
||||
** application in the system. Before this function can be
|
||||
** called, all connections must be removed with
|
||||
** AVCT_RemoveConn().
|
||||
**
|
||||
**
|
||||
** Returns void
|
||||
**
|
||||
*******************************************************************************/
|
||||
void AVCT_Deregister(void)
|
||||
{
|
||||
AVCT_TRACE_API("AVCT_Deregister");
|
||||
|
||||
/* deregister PSM with L2CAP */
|
||||
L2CA_Deregister(AVCT_PSM);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function AVCT_CreateConn
|
||||
**
|
||||
** Description Create an AVCTP connection. There are two types of
|
||||
** connections, initiator and acceptor, as determined by
|
||||
** the p_cc->role parameter. When this function is called to
|
||||
** create an initiator connection, an AVCTP connection to
|
||||
** the peer device is initiated if one does not already exist.
|
||||
** If an acceptor connection is created, the connection waits
|
||||
** passively for an incoming AVCTP connection from a peer device.
|
||||
**
|
||||
**
|
||||
** Returns AVCT_SUCCESS if successful, otherwise error.
|
||||
**
|
||||
*******************************************************************************/
|
||||
UINT16 AVCT_CreateConn(UINT8 *p_handle, tAVCT_CC *p_cc, BD_ADDR peer_addr)
|
||||
{
|
||||
UINT16 result = AVCT_SUCCESS;
|
||||
tAVCT_CCB *p_ccb;
|
||||
tAVCT_LCB *p_lcb;
|
||||
|
||||
AVCT_TRACE_API("AVCT_CreateConn: %d, control:%d", p_cc->role, p_cc->control);
|
||||
|
||||
/* Allocate ccb; if no ccbs, return failure */
|
||||
if ((p_ccb = avct_ccb_alloc(p_cc)) == NULL) {
|
||||
result = AVCT_NO_RESOURCES;
|
||||
} else {
|
||||
/* get handle */
|
||||
*p_handle = avct_ccb_to_idx(p_ccb);
|
||||
|
||||
/* if initiator connection */
|
||||
if (p_cc->role == AVCT_INT) {
|
||||
/* find link; if none allocate a new one */
|
||||
if ((p_lcb = avct_lcb_by_bd(peer_addr)) == NULL) {
|
||||
if ((p_lcb = avct_lcb_alloc(peer_addr)) == NULL) {
|
||||
/* no link resources; free ccb as well */
|
||||
avct_ccb_dealloc(p_ccb, AVCT_NO_EVT, 0, NULL);
|
||||
result = AVCT_NO_RESOURCES;
|
||||
}
|
||||
}
|
||||
/* check if PID already in use */
|
||||
else if (avct_lcb_has_pid(p_lcb, p_cc->pid)) {
|
||||
avct_ccb_dealloc(p_ccb, AVCT_NO_EVT, 0, NULL);
|
||||
result = AVCT_PID_IN_USE;
|
||||
}
|
||||
|
||||
if (result == AVCT_SUCCESS) {
|
||||
/* bind lcb to ccb */
|
||||
p_ccb->p_lcb = p_lcb;
|
||||
AVCT_TRACE_DEBUG("ch_state: %d", p_lcb->ch_state);
|
||||
avct_lcb_event(p_lcb, AVCT_LCB_UL_BIND_EVT, (tAVCT_LCB_EVT *) &p_ccb);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function AVCT_RemoveConn
|
||||
**
|
||||
** Description Remove an AVCTP connection. This function is called when
|
||||
** the application is no longer using a connection. If this
|
||||
** is the last connection to a peer the L2CAP channel for AVCTP
|
||||
** will be closed.
|
||||
**
|
||||
**
|
||||
** Returns AVCT_SUCCESS if successful, otherwise error.
|
||||
**
|
||||
*******************************************************************************/
|
||||
UINT16 AVCT_RemoveConn(UINT8 handle)
|
||||
{
|
||||
UINT16 result = AVCT_SUCCESS;
|
||||
tAVCT_CCB *p_ccb;
|
||||
|
||||
AVCT_TRACE_API("AVCT_RemoveConn");
|
||||
|
||||
/* map handle to ccb */
|
||||
if ((p_ccb = avct_ccb_by_idx(handle)) == NULL) {
|
||||
result = AVCT_BAD_HANDLE;
|
||||
}
|
||||
/* if connection not bound to lcb, dealloc */
|
||||
else if (p_ccb->p_lcb == NULL) {
|
||||
avct_ccb_dealloc(p_ccb, AVCT_NO_EVT, 0, NULL);
|
||||
}
|
||||
/* send unbind event to lcb */
|
||||
else {
|
||||
avct_lcb_event(p_ccb->p_lcb, AVCT_LCB_UL_UNBIND_EVT, (tAVCT_LCB_EVT *) &p_ccb);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function AVCT_CreateBrowse
|
||||
**
|
||||
** Description Create an AVCTP Browse channel. There are two types of
|
||||
** connections, initiator and acceptor, as determined by
|
||||
** the role parameter. When this function is called to
|
||||
** create an initiator connection, the Browse channel to
|
||||
** the peer device is initiated if one does not already exist.
|
||||
** If an acceptor connection is created, the connection waits
|
||||
** passively for an incoming AVCTP connection from a peer device.
|
||||
**
|
||||
**
|
||||
** Returns AVCT_SUCCESS if successful, otherwise error.
|
||||
**
|
||||
*******************************************************************************/
|
||||
UINT16 AVCT_CreateBrowse (UINT8 handle, UINT8 role)
|
||||
{
|
||||
#if (AVCT_BROWSE_INCLUDED == TRUE)
|
||||
UINT16 result = AVCT_SUCCESS;
|
||||
tAVCT_CCB *p_ccb;
|
||||
tAVCT_BCB *p_bcb;
|
||||
int index;
|
||||
|
||||
AVCT_TRACE_API("AVCT_CreateBrowse: %d", role);
|
||||
|
||||
/* map handle to ccb */
|
||||
if ((p_ccb = avct_ccb_by_idx(handle)) == NULL) {
|
||||
return AVCT_BAD_HANDLE;
|
||||
} else {
|
||||
/* mark this CCB as supporting browsing channel */
|
||||
if ((p_ccb->allocated & AVCT_ALOC_BCB) == 0) {
|
||||
p_ccb->allocated |= AVCT_ALOC_BCB;
|
||||
}
|
||||
}
|
||||
|
||||
/* if initiator connection */
|
||||
if (role == AVCT_INT) {
|
||||
/* the link control block must exist before this function is called as INT. */
|
||||
if ((p_ccb->p_lcb == NULL) || (p_ccb->p_lcb->allocated == 0)) {
|
||||
result = AVCT_NOT_OPEN;
|
||||
} else {
|
||||
/* find link; if none allocate a new one */
|
||||
index = p_ccb->p_lcb->allocated;
|
||||
if (index > AVCT_NUM_LINKS) {
|
||||
result = AVCT_BAD_HANDLE;
|
||||
} else {
|
||||
p_bcb = &avct_cb.bcb[index - 1];
|
||||
p_bcb->allocated = index;
|
||||
}
|
||||
}
|
||||
|
||||
if (result == AVCT_SUCCESS) {
|
||||
/* bind bcb to ccb */
|
||||
p_ccb->p_bcb = p_bcb;
|
||||
AVCT_TRACE_DEBUG("ch_state: %d", p_bcb->ch_state);
|
||||
avct_bcb_event(p_bcb, AVCT_LCB_UL_BIND_EVT, (tAVCT_LCB_EVT *) &p_ccb);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
#else
|
||||
UNUSED(handle);
|
||||
UNUSED(role);
|
||||
return AVCT_NO_RESOURCES;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function AVCT_RemoveBrowse
|
||||
**
|
||||
** Description Remove an AVCTP Browse channel. This function is called when
|
||||
** the application is no longer using a connection. If this
|
||||
** is the last connection to a peer the L2CAP channel for AVCTP
|
||||
** will be closed.
|
||||
**
|
||||
**
|
||||
** Returns AVCT_SUCCESS if successful, otherwise error.
|
||||
**
|
||||
*******************************************************************************/
|
||||
UINT16 AVCT_RemoveBrowse (UINT8 handle)
|
||||
{
|
||||
#if (AVCT_BROWSE_INCLUDED == TRUE)
|
||||
UINT16 result = AVCT_SUCCESS;
|
||||
tAVCT_CCB *p_ccb;
|
||||
|
||||
AVCT_TRACE_API("AVCT_RemoveBrowse");
|
||||
|
||||
/* map handle to ccb */
|
||||
if ((p_ccb = avct_ccb_by_idx(handle)) == NULL) {
|
||||
result = AVCT_BAD_HANDLE;
|
||||
} else if (p_ccb->p_bcb != NULL)
|
||||
/* send unbind event to bcb */
|
||||
{
|
||||
avct_bcb_event(p_ccb->p_bcb, AVCT_LCB_UL_UNBIND_EVT, (tAVCT_LCB_EVT *) &p_ccb);
|
||||
}
|
||||
return result;
|
||||
#else
|
||||
UNUSED(handle);
|
||||
return AVCT_NO_RESOURCES;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function AVCT_GetBrowseMtu
|
||||
**
|
||||
** Description Get the peer_mtu for the AVCTP Browse channel of the given
|
||||
** connection.
|
||||
**
|
||||
** Returns the peer browsing channel MTU.
|
||||
**
|
||||
*******************************************************************************/
|
||||
UINT16 AVCT_GetBrowseMtu (UINT8 handle)
|
||||
{
|
||||
UINT16 peer_mtu = AVCT_MIN_BROWSE_MTU;
|
||||
#if (AVCT_BROWSE_INCLUDED == TRUE)
|
||||
tAVCT_CCB *p_ccb;
|
||||
|
||||
if ((p_ccb = avct_ccb_by_idx(handle)) != NULL && p_ccb->p_bcb != NULL) {
|
||||
peer_mtu = p_ccb->p_bcb->peer_mtu;
|
||||
}
|
||||
#else
|
||||
UNUSED(handle);
|
||||
#endif
|
||||
return peer_mtu;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function AVCT_GetPeerMtu
|
||||
**
|
||||
** Description Get the peer_mtu for the AVCTP channel of the given
|
||||
** connection.
|
||||
**
|
||||
** Returns the peer MTU size.
|
||||
**
|
||||
*******************************************************************************/
|
||||
UINT16 AVCT_GetPeerMtu (UINT8 handle)
|
||||
{
|
||||
UINT16 peer_mtu = L2CAP_DEFAULT_MTU;
|
||||
tAVCT_CCB *p_ccb;
|
||||
|
||||
/* map handle to ccb */
|
||||
if ((p_ccb = avct_ccb_by_idx(handle)) != NULL) {
|
||||
if (p_ccb->p_lcb) {
|
||||
peer_mtu = p_ccb->p_lcb->peer_mtu;
|
||||
}
|
||||
}
|
||||
|
||||
return peer_mtu;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function AVCT_MsgReq
|
||||
**
|
||||
** Description Send an AVCTP message to a peer device. In calling
|
||||
** AVCT_MsgReq(), the application should keep track of the
|
||||
** congestion state of AVCTP as communicated with events
|
||||
** AVCT_CONG_IND_EVT and AVCT_UNCONG_IND_EVT. If the
|
||||
** application calls AVCT_MsgReq() when AVCTP is congested
|
||||
** the message may be discarded. The application may make its
|
||||
** first call to AVCT_MsgReq() after it receives an
|
||||
** AVCT_CONNECT_CFM_EVT or AVCT_CONNECT_IND_EVT on control channel or
|
||||
** AVCT_BROWSE_CONN_CFM_EVT or AVCT_BROWSE_CONN_IND_EVT on browsing channel.
|
||||
**
|
||||
** p_msg->layer_specific must be set to
|
||||
** AVCT_DATA_CTRL for control channel traffic;
|
||||
** AVCT_DATA_BROWSE for for browse channel traffic.
|
||||
**
|
||||
** Returns AVCT_SUCCESS if successful, otherwise error.
|
||||
**
|
||||
*******************************************************************************/
|
||||
UINT16 AVCT_MsgReq(UINT8 handle, UINT8 label, UINT8 cr, BT_HDR *p_msg)
|
||||
{
|
||||
UINT16 result = AVCT_SUCCESS;
|
||||
tAVCT_CCB *p_ccb;
|
||||
tAVCT_UL_MSG ul_msg;
|
||||
|
||||
AVCT_TRACE_API("AVCT_MsgReq");
|
||||
|
||||
/* verify p_msg parameter */
|
||||
if (p_msg == NULL) {
|
||||
return AVCT_NO_RESOURCES;
|
||||
}
|
||||
AVCT_TRACE_API("len: %d", p_msg->len);
|
||||
|
||||
/* map handle to ccb */
|
||||
if ((p_ccb = avct_ccb_by_idx(handle)) == NULL) {
|
||||
result = AVCT_BAD_HANDLE;
|
||||
osi_free(p_msg);
|
||||
}
|
||||
/* verify channel is bound to link */
|
||||
else if (p_ccb->p_lcb == NULL) {
|
||||
result = AVCT_NOT_OPEN;
|
||||
osi_free(p_msg);
|
||||
}
|
||||
|
||||
if (result == AVCT_SUCCESS) {
|
||||
ul_msg.p_buf = p_msg;
|
||||
ul_msg.p_ccb = p_ccb;
|
||||
ul_msg.label = label;
|
||||
ul_msg.cr = cr;
|
||||
|
||||
#if (AVCT_BROWSE_INCLUDED == TRUE)
|
||||
/* send msg event to bcb */
|
||||
if (p_msg->layer_specific == AVCT_DATA_BROWSE) {
|
||||
if (p_ccb->p_bcb == NULL && (p_ccb->allocated & AVCT_ALOC_BCB) == 0) {
|
||||
/* BCB channel is not open and not allocated */
|
||||
result = AVCT_BAD_HANDLE;
|
||||
osi_free(p_msg);
|
||||
} else {
|
||||
p_ccb->p_bcb = avct_bcb_by_lcb(p_ccb->p_lcb);
|
||||
avct_bcb_event(p_ccb->p_bcb, AVCT_LCB_UL_MSG_EVT, (tAVCT_LCB_EVT *) &ul_msg);
|
||||
}
|
||||
}
|
||||
/* send msg event to lcb */
|
||||
else
|
||||
#endif
|
||||
{
|
||||
avct_lcb_event(p_ccb->p_lcb, AVCT_LCB_UL_MSG_EVT, (tAVCT_LCB_EVT *) &ul_msg);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif /* #if (defined(AVCT_INCLUDED) && AVCT_INCLUDED == TRUE) */
|
||||
@@ -0,0 +1,145 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* Copyright (C) 2003-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 module contains functions which operate on the AVCTP connection
|
||||
* control block.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
#include <string.h>
|
||||
#include "stack/bt_types.h"
|
||||
#include "common/bt_target.h"
|
||||
#include "stack/avct_api.h"
|
||||
#include "avct_int.h"
|
||||
|
||||
#if (defined(AVCT_INCLUDED) && AVCT_INCLUDED == TRUE)
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function avct_ccb_alloc
|
||||
**
|
||||
** Description Allocate a connection control block; copy parameters to ccb.
|
||||
**
|
||||
**
|
||||
** Returns pointer to the ccb, or NULL if none could be allocated.
|
||||
**
|
||||
*******************************************************************************/
|
||||
tAVCT_CCB *avct_ccb_alloc(tAVCT_CC *p_cc)
|
||||
{
|
||||
tAVCT_CCB *p_ccb = &avct_cb.ccb[0];
|
||||
int i;
|
||||
|
||||
for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++) {
|
||||
if (!p_ccb->allocated) {
|
||||
p_ccb->allocated = AVCT_ALOC_LCB;
|
||||
memcpy(&p_ccb->cc, p_cc, sizeof(tAVCT_CC));
|
||||
AVCT_TRACE_DEBUG("avct_ccb_alloc %d", i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i == AVCT_NUM_CONN) {
|
||||
/* out of ccbs */
|
||||
p_ccb = NULL;
|
||||
AVCT_TRACE_WARNING("Out of ccbs");
|
||||
}
|
||||
return p_ccb;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function avct_ccb_dealloc
|
||||
**
|
||||
** Description Deallocate a connection control block and call application
|
||||
** callback.
|
||||
**
|
||||
**
|
||||
** Returns void.
|
||||
**
|
||||
*******************************************************************************/
|
||||
void avct_ccb_dealloc(tAVCT_CCB *p_ccb, UINT8 event, UINT16 result, BD_ADDR bd_addr)
|
||||
{
|
||||
tAVCT_CTRL_CBACK *p_cback = p_ccb->cc.p_ctrl_cback;
|
||||
|
||||
AVCT_TRACE_DEBUG("avct_ccb_dealloc %d", avct_ccb_to_idx(p_ccb));
|
||||
#if (AVCT_BROWSE_INCLUDED == TRUE)
|
||||
if (p_ccb->p_bcb == NULL) {
|
||||
memset(p_ccb, 0, sizeof(tAVCT_CCB));
|
||||
} else {
|
||||
/* control channel is down, but the browsing channel is still connected 0 disconnect it now */
|
||||
avct_bcb_event(p_ccb->p_bcb, AVCT_LCB_UL_UNBIND_EVT, (tAVCT_LCB_EVT *) &p_ccb);
|
||||
p_ccb->p_lcb = NULL;
|
||||
}
|
||||
#else
|
||||
memset(p_ccb, 0, sizeof(tAVCT_CCB));
|
||||
#endif
|
||||
|
||||
if (event != AVCT_NO_EVT) {
|
||||
(*p_cback)(avct_ccb_to_idx(p_ccb), event, result, bd_addr);
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function avct_ccb_to_idx
|
||||
**
|
||||
** Description Given a pointer to an ccb, return its index.
|
||||
**
|
||||
**
|
||||
** Returns Index of ccb.
|
||||
**
|
||||
*******************************************************************************/
|
||||
UINT8 avct_ccb_to_idx(tAVCT_CCB *p_ccb)
|
||||
{
|
||||
/* use array arithmetic to determine index */
|
||||
return (UINT8) (p_ccb - avct_cb.ccb);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function avct_ccb_by_idx
|
||||
**
|
||||
** Description Return ccb pointer based on ccb index (or handle).
|
||||
**
|
||||
**
|
||||
** Returns pointer to the ccb, or NULL if none found.
|
||||
**
|
||||
*******************************************************************************/
|
||||
tAVCT_CCB *avct_ccb_by_idx(UINT8 idx)
|
||||
{
|
||||
tAVCT_CCB *p_ccb;
|
||||
|
||||
/* verify index */
|
||||
if (idx < AVCT_NUM_CONN) {
|
||||
p_ccb = &avct_cb.ccb[idx];
|
||||
|
||||
/* verify ccb is allocated */
|
||||
if (!p_ccb->allocated) {
|
||||
p_ccb = NULL;
|
||||
AVCT_TRACE_WARNING("ccb %d not allocated", idx);
|
||||
}
|
||||
} else {
|
||||
p_ccb = NULL;
|
||||
AVCT_TRACE_WARNING("No ccb for idx %d", idx);
|
||||
}
|
||||
return p_ccb;
|
||||
}
|
||||
|
||||
#endif /* #if (defined(AVCT_INCLUDED) && AVCT_INCLUDED == TRUE) */
|
||||
@@ -0,0 +1,406 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* Copyright (C) 2003-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 AVCTP module interfaces to L2CAP
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
#include <string.h>
|
||||
#include "stack/bt_types.h"
|
||||
#include "common/bt_target.h"
|
||||
#include "common/bt_defs.h"
|
||||
#include "stack/avct_api.h"
|
||||
#include "avct_int.h"
|
||||
#include "stack/l2c_api.h"
|
||||
#include "stack/l2cdefs.h"
|
||||
#include "osi/allocator.h"
|
||||
|
||||
#if (defined(AVCT_INCLUDED) && AVCT_INCLUDED == TRUE)
|
||||
|
||||
/* Configuration flags. */
|
||||
#define AVCT_L2C_CFG_IND_DONE (1<<0)
|
||||
#define AVCT_L2C_CFG_CFM_DONE (1<<1)
|
||||
|
||||
/* callback function declarations */
|
||||
void avct_l2c_connect_ind_cback(BD_ADDR bd_addr, UINT16 lcid, UINT16 psm, UINT8 id);
|
||||
void avct_l2c_connect_cfm_cback(UINT16 lcid, UINT16 result);
|
||||
void avct_l2c_config_cfm_cback(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg);
|
||||
void avct_l2c_config_ind_cback(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg);
|
||||
void avct_l2c_disconnect_ind_cback(UINT16 lcid, BOOLEAN ack_needed);
|
||||
void avct_l2c_disconnect_cfm_cback(UINT16 lcid, UINT16 result);
|
||||
void avct_l2c_congestion_ind_cback(UINT16 lcid, BOOLEAN is_congested);
|
||||
void avct_l2c_data_ind_cback(UINT16 lcid, BT_HDR *p_buf);
|
||||
|
||||
/* L2CAP callback function structure */
|
||||
const tL2CAP_APPL_INFO avct_l2c_appl = {
|
||||
avct_l2c_connect_ind_cback,
|
||||
avct_l2c_connect_cfm_cback,
|
||||
NULL,
|
||||
avct_l2c_config_ind_cback,
|
||||
avct_l2c_config_cfm_cback,
|
||||
avct_l2c_disconnect_ind_cback,
|
||||
avct_l2c_disconnect_cfm_cback,
|
||||
NULL,
|
||||
avct_l2c_data_ind_cback,
|
||||
avct_l2c_congestion_ind_cback,
|
||||
NULL /* tL2CA_TX_COMPLETE_CB */
|
||||
};
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function avct_l2c_is_passive
|
||||
**
|
||||
** Description check is the CCB associated with the given LCB was created
|
||||
** as passive
|
||||
**
|
||||
** Returns TRUE, if the given LCB is created as AVCT_PASSIVE
|
||||
**
|
||||
*******************************************************************************/
|
||||
static BOOLEAN avct_l2c_is_passive (tAVCT_LCB *p_lcb)
|
||||
{
|
||||
BOOLEAN is_passive = FALSE;
|
||||
tAVCT_CCB *p_ccb = &avct_cb.ccb[0];
|
||||
int i;
|
||||
|
||||
for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++) {
|
||||
if (p_ccb->allocated && (p_ccb->p_lcb == p_lcb)) {
|
||||
AVCT_TRACE_DEBUG("avct_l2c_is_ct control:x%x", p_ccb->cc.control);
|
||||
if (p_ccb->cc.control & AVCT_PASSIVE) {
|
||||
is_passive = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return is_passive;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function avct_l2c_connect_ind_cback
|
||||
**
|
||||
** Description This is the L2CAP connect indication callback function.
|
||||
**
|
||||
**
|
||||
** Returns void
|
||||
**
|
||||
*******************************************************************************/
|
||||
void avct_l2c_connect_ind_cback(BD_ADDR bd_addr, UINT16 lcid, UINT16 psm, UINT8 id)
|
||||
{
|
||||
tAVCT_LCB *p_lcb;
|
||||
UINT16 result = L2CAP_CONN_OK;
|
||||
tL2CAP_CFG_INFO cfg;
|
||||
UNUSED(psm);
|
||||
|
||||
/* do we already have a channel for this peer? */
|
||||
if ((p_lcb = avct_lcb_by_bd(bd_addr)) == NULL) {
|
||||
/* no, allocate lcb */
|
||||
if ((p_lcb = avct_lcb_alloc(bd_addr)) == NULL) {
|
||||
/* no ccb available, reject L2CAP connection */
|
||||
result = L2CAP_CONN_NO_RESOURCES;
|
||||
}
|
||||
}
|
||||
/* else we already have a channel for this peer */
|
||||
else {
|
||||
if (!avct_l2c_is_passive (p_lcb) || (p_lcb->ch_state == AVCT_CH_OPEN)) {
|
||||
/* this LCB included CT role - reject */
|
||||
result = L2CAP_CONN_NO_RESOURCES;
|
||||
} else {
|
||||
/* TG role only - accept the connection from CT. move the channel ID to the conflict list */
|
||||
p_lcb->conflict_lcid = p_lcb->ch_lcid;
|
||||
AVCT_TRACE_DEBUG("avct_l2c_connect_ind_cback conflict_lcid:0x%x", p_lcb->conflict_lcid);
|
||||
}
|
||||
}
|
||||
|
||||
if (p_lcb) {
|
||||
AVCT_TRACE_DEBUG("avct_l2c_connect_ind_cback: 0x%x, res: %d, ch_state: %d",
|
||||
lcid, result, p_lcb->ch_state);
|
||||
}
|
||||
/* Send L2CAP connect rsp */
|
||||
L2CA_ConnectRsp(bd_addr, id, lcid, result, 0);
|
||||
|
||||
/* if result ok, proceed with connection */
|
||||
if (result == L2CAP_CONN_OK) {
|
||||
/* store LCID */
|
||||
p_lcb->ch_lcid = lcid;
|
||||
|
||||
/* transition to configuration state */
|
||||
p_lcb->ch_state = AVCT_CH_CFG;
|
||||
|
||||
/* Send L2CAP config req */
|
||||
memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
|
||||
cfg.mtu_present = TRUE;
|
||||
cfg.mtu = avct_cb.mtu;
|
||||
L2CA_ConfigReq(lcid, &cfg);
|
||||
AVCT_TRACE_DEBUG("avct_l2c snd Cfg Req");
|
||||
}
|
||||
|
||||
#if (BT_USE_TRACES == TRUE)
|
||||
if (p_lcb) {
|
||||
AVCT_TRACE_DEBUG("ch_state cni: %d ", p_lcb->ch_state);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function avct_l2c_connect_cfm_cback
|
||||
**
|
||||
** Description This is the L2CAP connect confirm callback function.
|
||||
**
|
||||
**
|
||||
** Returns void
|
||||
**
|
||||
*******************************************************************************/
|
||||
void avct_l2c_connect_cfm_cback(UINT16 lcid, UINT16 result)
|
||||
{
|
||||
tAVCT_LCB *p_lcb;
|
||||
tL2CAP_CFG_INFO cfg;
|
||||
|
||||
/* look up lcb for this channel */
|
||||
if ((p_lcb = avct_lcb_by_lcid(lcid)) != NULL) {
|
||||
AVCT_TRACE_DEBUG("avct_l2c_connect_cfm_cback lcid:0x%x result: %d ch_state: %d, conflict_lcid:0x%x",
|
||||
lcid, result, p_lcb->ch_state, p_lcb->conflict_lcid);
|
||||
/* if in correct state */
|
||||
if (p_lcb->ch_state == AVCT_CH_CONN) {
|
||||
/* if result successful */
|
||||
if (result == L2CAP_CONN_OK) {
|
||||
/* set channel state */
|
||||
p_lcb->ch_state = AVCT_CH_CFG;
|
||||
|
||||
/* Send L2CAP config req */
|
||||
memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
|
||||
cfg.mtu_present = TRUE;
|
||||
cfg.mtu = avct_cb.mtu;
|
||||
L2CA_ConfigReq(lcid, &cfg);
|
||||
AVCT_TRACE_DEBUG("avct_l2c snd Cfg Req");
|
||||
}
|
||||
/* else failure */
|
||||
else {
|
||||
AVCT_TRACE_DEBUG("avct_l2c_connect_cfm_cback conflict_lcid:0x%x", p_lcb->conflict_lcid);
|
||||
if (p_lcb->conflict_lcid == lcid) {
|
||||
p_lcb->conflict_lcid = 0;
|
||||
} else {
|
||||
avct_lcb_event(p_lcb, AVCT_LCB_LL_CLOSE_EVT, (tAVCT_LCB_EVT *) &result);
|
||||
}
|
||||
}
|
||||
} else if (p_lcb->conflict_lcid == lcid) {
|
||||
/* we must be in AVCT_CH_CFG state for the ch_lcid channel */
|
||||
AVCT_TRACE_DEBUG("avct_l2c_connect_cfm_cback ch_state: %d, conflict_lcid:0x%x", p_lcb->ch_state, p_lcb->conflict_lcid);
|
||||
if (result == L2CAP_CONN_OK) {
|
||||
/* just in case the peer also accepts our connection - Send L2CAP disconnect req */
|
||||
L2CA_DisconnectReq(lcid);
|
||||
}
|
||||
p_lcb->conflict_lcid = 0;
|
||||
}
|
||||
AVCT_TRACE_DEBUG("ch_state cnc: %d ", p_lcb->ch_state);
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function avct_l2c_config_cfm_cback
|
||||
**
|
||||
** Description This is the L2CAP config confirm callback function.
|
||||
**
|
||||
**
|
||||
** Returns void
|
||||
**
|
||||
*******************************************************************************/
|
||||
void avct_l2c_config_cfm_cback(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg)
|
||||
{
|
||||
tAVCT_LCB *p_lcb;
|
||||
|
||||
/* look up lcb for this channel */
|
||||
if ((p_lcb = avct_lcb_by_lcid(lcid)) != NULL) {
|
||||
AVCT_TRACE_DEBUG("avct_l2c_config_cfm_cback: 0x%x, ch_state: %d, res: %d",
|
||||
lcid, p_lcb->ch_state, p_cfg->result);
|
||||
/* if in correct state */
|
||||
if (p_lcb->ch_state == AVCT_CH_CFG) {
|
||||
/* if result successful */
|
||||
if (p_cfg->result == L2CAP_CFG_OK) {
|
||||
/* update flags */
|
||||
p_lcb->ch_flags |= AVCT_L2C_CFG_CFM_DONE;
|
||||
|
||||
/* if configuration complete */
|
||||
if (p_lcb->ch_flags & AVCT_L2C_CFG_IND_DONE) {
|
||||
p_lcb->ch_state = AVCT_CH_OPEN;
|
||||
avct_lcb_event(p_lcb, AVCT_LCB_LL_OPEN_EVT, NULL);
|
||||
}
|
||||
}
|
||||
/* else failure */
|
||||
else {
|
||||
AVCT_TRACE_DEBUG("ERROR avct_l2c_config_cfm_cback L2CA_DisconnectReq %d ", p_lcb->ch_state);
|
||||
/* store result value */
|
||||
p_lcb->ch_result = p_cfg->result;
|
||||
|
||||
/* Send L2CAP disconnect req */
|
||||
L2CA_DisconnectReq(lcid);
|
||||
}
|
||||
}
|
||||
AVCT_TRACE_DEBUG("ch_state cfc: %d ", p_lcb->ch_state);
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function avct_l2c_config_ind_cback
|
||||
**
|
||||
** Description This is the L2CAP config indication callback function.
|
||||
**
|
||||
**
|
||||
** Returns void
|
||||
**
|
||||
*******************************************************************************/
|
||||
void avct_l2c_config_ind_cback(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg)
|
||||
{
|
||||
tAVCT_LCB *p_lcb;
|
||||
|
||||
/* look up lcb for this channel */
|
||||
if ((p_lcb = avct_lcb_by_lcid(lcid)) != NULL) {
|
||||
AVCT_TRACE_DEBUG("avct_l2c_config_ind_cback: 0x%x, ch_state: %d", lcid, p_lcb->ch_state);
|
||||
/* store the mtu in tbl */
|
||||
if (p_cfg->mtu_present) {
|
||||
p_lcb->peer_mtu = p_cfg->mtu;
|
||||
} else {
|
||||
p_lcb->peer_mtu = L2CAP_DEFAULT_MTU;
|
||||
}
|
||||
|
||||
/* send L2CAP configure response */
|
||||
memset(p_cfg, 0, sizeof(tL2CAP_CFG_INFO));
|
||||
p_cfg->result = L2CAP_CFG_OK;
|
||||
L2CA_ConfigRsp(lcid, p_cfg);
|
||||
|
||||
/* if first config ind */
|
||||
if ((p_lcb->ch_flags & AVCT_L2C_CFG_IND_DONE) == 0) {
|
||||
/* update flags */
|
||||
p_lcb->ch_flags |= AVCT_L2C_CFG_IND_DONE;
|
||||
|
||||
/* if configuration complete */
|
||||
if (p_lcb->ch_flags & AVCT_L2C_CFG_CFM_DONE) {
|
||||
p_lcb->ch_state = AVCT_CH_OPEN;
|
||||
avct_lcb_event(p_lcb, AVCT_LCB_LL_OPEN_EVT, NULL);
|
||||
}
|
||||
}
|
||||
AVCT_TRACE_DEBUG("ch_state cfi: %d ", p_lcb->ch_state);
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function avct_l2c_disconnect_ind_cback
|
||||
**
|
||||
** Description This is the L2CAP disconnect indication callback function.
|
||||
**
|
||||
**
|
||||
** Returns void
|
||||
**
|
||||
*******************************************************************************/
|
||||
void avct_l2c_disconnect_ind_cback(UINT16 lcid, BOOLEAN ack_needed)
|
||||
{
|
||||
tAVCT_LCB *p_lcb;
|
||||
UINT16 result = AVCT_RESULT_FAIL;
|
||||
|
||||
/* look up lcb for this channel */
|
||||
if ((p_lcb = avct_lcb_by_lcid(lcid)) != NULL) {
|
||||
AVCT_TRACE_DEBUG("avct_l2c_disconnect_ind_cback: 0x%x, ch_state: %d", lcid, p_lcb->ch_state);
|
||||
if (ack_needed) {
|
||||
/* send L2CAP disconnect response */
|
||||
L2CA_DisconnectRsp(lcid);
|
||||
}
|
||||
|
||||
avct_lcb_event(p_lcb, AVCT_LCB_LL_CLOSE_EVT, (tAVCT_LCB_EVT *) &result);
|
||||
AVCT_TRACE_DEBUG("ch_state di: %d ", p_lcb->ch_state);
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function avct_l2c_disconnect_cfm_cback
|
||||
**
|
||||
** Description This is the L2CAP disconnect confirm callback function.
|
||||
**
|
||||
**
|
||||
** Returns void
|
||||
**
|
||||
*******************************************************************************/
|
||||
void avct_l2c_disconnect_cfm_cback(UINT16 lcid, UINT16 result)
|
||||
{
|
||||
tAVCT_LCB *p_lcb;
|
||||
UINT16 res;
|
||||
|
||||
/* look up lcb for this channel */
|
||||
if ((p_lcb = avct_lcb_by_lcid(lcid)) != NULL) {
|
||||
AVCT_TRACE_DEBUG("avct_l2c_disconnect_cfm_cback: 0x%x, ch_state: %d, res: %d",
|
||||
lcid, p_lcb->ch_state, result);
|
||||
/* result value may be previously stored */
|
||||
res = (p_lcb->ch_result != 0) ? p_lcb->ch_result : result;
|
||||
p_lcb->ch_result = 0;
|
||||
|
||||
avct_lcb_event(p_lcb, AVCT_LCB_LL_CLOSE_EVT, (tAVCT_LCB_EVT *) &res);
|
||||
AVCT_TRACE_DEBUG("ch_state dc: %d ", p_lcb->ch_state);
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function avct_l2c_congestion_ind_cback
|
||||
**
|
||||
** Description This is the L2CAP congestion indication callback function.
|
||||
**
|
||||
**
|
||||
** Returns void
|
||||
**
|
||||
*******************************************************************************/
|
||||
void avct_l2c_congestion_ind_cback(UINT16 lcid, BOOLEAN is_congested)
|
||||
{
|
||||
tAVCT_LCB *p_lcb;
|
||||
|
||||
AVCT_TRACE_DEBUG("avct_l2c_congestion_ind_cback: 0x%x", lcid);
|
||||
/* look up lcb for this channel */
|
||||
if ((p_lcb = avct_lcb_by_lcid(lcid)) != NULL) {
|
||||
avct_lcb_event(p_lcb, AVCT_LCB_LL_CONG_EVT, (tAVCT_LCB_EVT *) &is_congested);
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function avct_l2c_data_ind_cback
|
||||
**
|
||||
** Description This is the L2CAP data indication callback function.
|
||||
**
|
||||
**
|
||||
** Returns void
|
||||
**
|
||||
*******************************************************************************/
|
||||
void avct_l2c_data_ind_cback(UINT16 lcid, BT_HDR *p_buf)
|
||||
{
|
||||
tAVCT_LCB *p_lcb;
|
||||
|
||||
AVCT_TRACE_DEBUG("avct_l2c_data_ind_cback: 0x%x", lcid);
|
||||
/* look up lcb for this channel */
|
||||
if ((p_lcb = avct_lcb_by_lcid(lcid)) != NULL) {
|
||||
avct_lcb_event(p_lcb, AVCT_LCB_LL_MSG_EVT, (tAVCT_LCB_EVT *) &p_buf);
|
||||
} else { /* prevent buffer leak */
|
||||
AVCT_TRACE_WARNING("ERROR -> avct_l2c_data_ind_cback drop buffer");
|
||||
osi_free(p_buf);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* #if (defined(AVCT_INCLUDED) && AVCT_INCLUDED == TRUE) */
|
||||
@@ -0,0 +1,445 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* Copyright (C) 2003-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 module contains the link control state machine and functions which
|
||||
* operate on the link control block.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
#include <string.h>
|
||||
#include "stack/bt_types.h"
|
||||
#include "common/bt_target.h"
|
||||
#include "common/bt_defs.h"
|
||||
#include "stack/avct_api.h"
|
||||
#include "avct_int.h"
|
||||
#include "osi/allocator.h"
|
||||
|
||||
#if (defined(AVCT_INCLUDED) && AVCT_INCLUDED == TRUE)
|
||||
|
||||
/*****************************************************************************
|
||||
** state machine constants and types
|
||||
*****************************************************************************/
|
||||
|
||||
#if BT_TRACE_VERBOSE == TRUE
|
||||
|
||||
/* verbose state strings for trace */
|
||||
const char *const avct_lcb_st_str[] = {
|
||||
"LCB_IDLE_ST",
|
||||
"LCB_OPENING_ST",
|
||||
"LCB_OPEN_ST",
|
||||
"LCB_CLOSING_ST"
|
||||
};
|
||||
|
||||
/* verbose event strings for trace */
|
||||
const char *const avct_lcb_evt_str[] = {
|
||||
"UL_BIND_EVT",
|
||||
"UL_UNBIND_EVT",
|
||||
"UL_MSG_EVT",
|
||||
"INT_CLOSE_EVT",
|
||||
"LL_OPEN_EVT",
|
||||
"LL_CLOSE_EVT",
|
||||
"LL_MSG_EVT",
|
||||
"LL_CONG_EVT"
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
/* lcb state machine states */
|
||||
enum {
|
||||
AVCT_LCB_IDLE_ST,
|
||||
AVCT_LCB_OPENING_ST,
|
||||
AVCT_LCB_OPEN_ST,
|
||||
AVCT_LCB_CLOSING_ST
|
||||
};
|
||||
|
||||
/* state machine action enumeration list */
|
||||
enum {
|
||||
AVCT_LCB_CHNL_OPEN,
|
||||
AVCT_LCB_CHNL_DISC,
|
||||
AVCT_LCB_SEND_MSG,
|
||||
AVCT_LCB_OPEN_IND,
|
||||
AVCT_LCB_OPEN_FAIL,
|
||||
AVCT_LCB_CLOSE_IND,
|
||||
AVCT_LCB_CLOSE_CFM,
|
||||
AVCT_LCB_MSG_IND,
|
||||
AVCT_LCB_CONG_IND,
|
||||
AVCT_LCB_BIND_CONN,
|
||||
AVCT_LCB_BIND_FAIL,
|
||||
AVCT_LCB_UNBIND_DISC,
|
||||
AVCT_LCB_CHK_DISC,
|
||||
AVCT_LCB_DISCARD_MSG,
|
||||
AVCT_LCB_DEALLOC,
|
||||
AVCT_LCB_FREE_MSG_IND,
|
||||
AVCT_LCB_NUM_ACTIONS
|
||||
};
|
||||
|
||||
#define AVCT_LCB_IGNORE AVCT_LCB_NUM_ACTIONS
|
||||
|
||||
/* type for action functions */
|
||||
typedef void (*tAVCT_LCB_ACTION)(tAVCT_LCB *p_ccb, tAVCT_LCB_EVT *p_data);
|
||||
|
||||
/* action function list */
|
||||
const tAVCT_LCB_ACTION avct_lcb_action[] = {
|
||||
avct_lcb_chnl_open,
|
||||
avct_lcb_chnl_disc,
|
||||
avct_lcb_send_msg,
|
||||
avct_lcb_open_ind,
|
||||
avct_lcb_open_fail,
|
||||
avct_lcb_close_ind,
|
||||
avct_lcb_close_cfm,
|
||||
avct_lcb_msg_ind,
|
||||
avct_lcb_cong_ind,
|
||||
avct_lcb_bind_conn,
|
||||
avct_lcb_bind_fail,
|
||||
avct_lcb_unbind_disc,
|
||||
avct_lcb_chk_disc,
|
||||
avct_lcb_discard_msg,
|
||||
avct_lcb_dealloc,
|
||||
avct_lcb_free_msg_ind
|
||||
};
|
||||
|
||||
/* state table information */
|
||||
#define AVCT_LCB_ACTIONS 2 /* number of actions */
|
||||
#define AVCT_LCB_NEXT_STATE 2 /* position of next state */
|
||||
#define AVCT_LCB_NUM_COLS 3 /* number of columns in state tables */
|
||||
|
||||
/* state table for idle state */
|
||||
const UINT8 avct_lcb_st_idle[][AVCT_LCB_NUM_COLS] = {
|
||||
/* Event Action 1 Action 2 Next state */
|
||||
/* UL_BIND_EVT */ {AVCT_LCB_CHNL_OPEN, AVCT_LCB_IGNORE, AVCT_LCB_OPENING_ST},
|
||||
/* UL_UNBIND_EVT */ {AVCT_LCB_UNBIND_DISC, AVCT_LCB_IGNORE, AVCT_LCB_IDLE_ST},
|
||||
/* UL_MSG_EVT */ {AVCT_LCB_DISCARD_MSG, AVCT_LCB_IGNORE, AVCT_LCB_IDLE_ST},
|
||||
/* INT_CLOSE_EVT */ {AVCT_LCB_IGNORE, AVCT_LCB_IGNORE, AVCT_LCB_IDLE_ST},
|
||||
/* LL_OPEN_EVT */ {AVCT_LCB_OPEN_IND, AVCT_LCB_IGNORE, AVCT_LCB_OPEN_ST},
|
||||
/* LL_CLOSE_EVT */ {AVCT_LCB_CLOSE_IND, AVCT_LCB_DEALLOC, AVCT_LCB_IDLE_ST},
|
||||
/* LL_MSG_EVT */ {AVCT_LCB_FREE_MSG_IND, AVCT_LCB_IGNORE, AVCT_LCB_IDLE_ST},
|
||||
/* LL_CONG_EVT */ {AVCT_LCB_IGNORE, AVCT_LCB_IGNORE, AVCT_LCB_IDLE_ST}
|
||||
};
|
||||
|
||||
/* state table for opening state */
|
||||
const UINT8 avct_lcb_st_opening[][AVCT_LCB_NUM_COLS] = {
|
||||
/* Event Action 1 Action 2 Next state */
|
||||
/* UL_BIND_EVT */ {AVCT_LCB_IGNORE, AVCT_LCB_IGNORE, AVCT_LCB_OPENING_ST},
|
||||
/* UL_UNBIND_EVT */ {AVCT_LCB_UNBIND_DISC, AVCT_LCB_IGNORE, AVCT_LCB_OPENING_ST},
|
||||
/* UL_MSG_EVT */ {AVCT_LCB_DISCARD_MSG, AVCT_LCB_IGNORE, AVCT_LCB_OPENING_ST},
|
||||
/* INT_CLOSE_EVT */ {AVCT_LCB_CHNL_DISC, AVCT_LCB_IGNORE, AVCT_LCB_CLOSING_ST},
|
||||
/* LL_OPEN_EVT */ {AVCT_LCB_OPEN_IND, AVCT_LCB_IGNORE, AVCT_LCB_OPEN_ST},
|
||||
/* LL_CLOSE_EVT */ {AVCT_LCB_OPEN_FAIL, AVCT_LCB_DEALLOC, AVCT_LCB_IDLE_ST},
|
||||
/* LL_MSG_EVT */ {AVCT_LCB_FREE_MSG_IND, AVCT_LCB_IGNORE, AVCT_LCB_OPENING_ST},
|
||||
/* LL_CONG_EVT */ {AVCT_LCB_CONG_IND, AVCT_LCB_IGNORE, AVCT_LCB_OPENING_ST}
|
||||
};
|
||||
|
||||
/* state table for open state */
|
||||
const UINT8 avct_lcb_st_open[][AVCT_LCB_NUM_COLS] = {
|
||||
/* Event Action 1 Action 2 Next state */
|
||||
/* UL_BIND_EVT */ {AVCT_LCB_BIND_CONN, AVCT_LCB_IGNORE, AVCT_LCB_OPEN_ST},
|
||||
/* UL_UNBIND_EVT */ {AVCT_LCB_CHK_DISC, AVCT_LCB_IGNORE, AVCT_LCB_OPEN_ST},
|
||||
/* UL_MSG_EVT */ {AVCT_LCB_SEND_MSG, AVCT_LCB_IGNORE, AVCT_LCB_OPEN_ST},
|
||||
/* INT_CLOSE_EVT */ {AVCT_LCB_CHNL_DISC, AVCT_LCB_IGNORE, AVCT_LCB_CLOSING_ST},
|
||||
/* LL_OPEN_EVT */ {AVCT_LCB_IGNORE, AVCT_LCB_IGNORE, AVCT_LCB_OPEN_ST},
|
||||
/* LL_CLOSE_EVT */ {AVCT_LCB_CLOSE_IND, AVCT_LCB_DEALLOC, AVCT_LCB_IDLE_ST},
|
||||
/* LL_MSG_EVT */ {AVCT_LCB_MSG_IND, AVCT_LCB_IGNORE, AVCT_LCB_OPEN_ST},
|
||||
/* LL_CONG_EVT */ {AVCT_LCB_CONG_IND, AVCT_LCB_IGNORE, AVCT_LCB_OPEN_ST}
|
||||
};
|
||||
|
||||
/* state table for closing state */
|
||||
const UINT8 avct_lcb_st_closing[][AVCT_LCB_NUM_COLS] = {
|
||||
/* Event Action 1 Action 2 Next state */
|
||||
/* UL_BIND_EVT */ {AVCT_LCB_BIND_FAIL, AVCT_LCB_IGNORE, AVCT_LCB_CLOSING_ST},
|
||||
/* UL_UNBIND_EVT */ {AVCT_LCB_IGNORE, AVCT_LCB_IGNORE, AVCT_LCB_CLOSING_ST},
|
||||
/* UL_MSG_EVT */ {AVCT_LCB_DISCARD_MSG, AVCT_LCB_IGNORE, AVCT_LCB_CLOSING_ST},
|
||||
/* INT_CLOSE_EVT */ {AVCT_LCB_IGNORE, AVCT_LCB_IGNORE, AVCT_LCB_CLOSING_ST},
|
||||
/* LL_OPEN_EVT */ {AVCT_LCB_IGNORE, AVCT_LCB_IGNORE, AVCT_LCB_CLOSING_ST},
|
||||
/* LL_CLOSE_EVT */ {AVCT_LCB_CLOSE_CFM, AVCT_LCB_DEALLOC, AVCT_LCB_IDLE_ST},
|
||||
/* LL_MSG_EVT */ {AVCT_LCB_FREE_MSG_IND, AVCT_LCB_IGNORE, AVCT_LCB_CLOSING_ST},
|
||||
/* LL_CONG_EVT */ {AVCT_LCB_IGNORE, AVCT_LCB_IGNORE, AVCT_LCB_CLOSING_ST}
|
||||
};
|
||||
|
||||
/* type for state table */
|
||||
typedef const UINT8 (*tAVCT_LCB_ST_TBL)[AVCT_LCB_NUM_COLS];
|
||||
|
||||
/* state table */
|
||||
const tAVCT_LCB_ST_TBL avct_lcb_st_tbl[] = {
|
||||
avct_lcb_st_idle,
|
||||
avct_lcb_st_opening,
|
||||
avct_lcb_st_open,
|
||||
avct_lcb_st_closing
|
||||
};
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function avct_lcb_event
|
||||
**
|
||||
** Description State machine event handling function for lcb
|
||||
**
|
||||
**
|
||||
** Returns Nothing.
|
||||
**
|
||||
*******************************************************************************/
|
||||
void avct_lcb_event(tAVCT_LCB *p_lcb, UINT8 event, tAVCT_LCB_EVT *p_data)
|
||||
{
|
||||
tAVCT_LCB_ST_TBL state_table;
|
||||
UINT8 action;
|
||||
int i;
|
||||
|
||||
#if BT_TRACE_VERBOSE == TRUE
|
||||
AVCT_TRACE_EVENT("LCB lcb=%d event=%s state=%s", p_lcb->allocated, avct_lcb_evt_str[event], avct_lcb_st_str[p_lcb->state]);
|
||||
#else
|
||||
AVCT_TRACE_EVENT("LCB lcb=%d event=%d state=%d", p_lcb->allocated, event, p_lcb->state);
|
||||
#endif
|
||||
|
||||
/* look up the state table for the current state */
|
||||
state_table = avct_lcb_st_tbl[p_lcb->state];
|
||||
|
||||
/* set next state */
|
||||
p_lcb->state = state_table[event][AVCT_LCB_NEXT_STATE];
|
||||
|
||||
/* execute action functions */
|
||||
for (i = 0; i < AVCT_LCB_ACTIONS; i++) {
|
||||
if ((action = state_table[event][i]) != AVCT_LCB_IGNORE) {
|
||||
(*avct_lcb_action[action])(p_lcb, p_data);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function avct_bcb_event
|
||||
**
|
||||
** Description State machine event handling function for lcb
|
||||
**
|
||||
**
|
||||
** Returns Nothing.
|
||||
**
|
||||
*******************************************************************************/
|
||||
#if (AVCT_BROWSE_INCLUDED == TRUE)
|
||||
void avct_bcb_event(tAVCT_BCB *p_bcb, UINT8 event, tAVCT_LCB_EVT *p_data)
|
||||
{
|
||||
tAVCT_LCB_ST_TBL state_table;
|
||||
UINT8 action;
|
||||
int i;
|
||||
|
||||
#if BT_TRACE_VERBOSE == TRUE
|
||||
AVCT_TRACE_EVENT("BCB lcb=%d event=%s state=%s", p_bcb->allocated, avct_lcb_evt_str[event], avct_lcb_st_str[p_bcb->state]);
|
||||
#else
|
||||
AVCT_TRACE_EVENT("BCB lcb=%d event=%d state=%d", p_bcb->allocated, event, p_bcb->state);
|
||||
#endif
|
||||
|
||||
/* look up the state table for the current state */
|
||||
state_table = avct_lcb_st_tbl[p_bcb->state];
|
||||
|
||||
/* set next state */
|
||||
p_bcb->state = state_table[event][AVCT_LCB_NEXT_STATE];
|
||||
|
||||
/* execute action functions */
|
||||
for (i = 0; i < AVCT_LCB_ACTIONS; i++) {
|
||||
if ((action = state_table[event][i]) != AVCT_LCB_IGNORE) {
|
||||
(*avct_bcb_action[action])(p_bcb, p_data);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function avct_lcb_by_bd
|
||||
**
|
||||
** Description This lookup function finds the lcb for a BD address.
|
||||
**
|
||||
**
|
||||
** Returns pointer to the lcb, or NULL if none found.
|
||||
**
|
||||
*******************************************************************************/
|
||||
tAVCT_LCB *avct_lcb_by_bd(BD_ADDR bd_addr)
|
||||
{
|
||||
tAVCT_LCB *p_lcb = &avct_cb.lcb[0];
|
||||
int i;
|
||||
|
||||
for (i = 0; i < AVCT_NUM_LINKS; i++, p_lcb++) {
|
||||
/* if allocated lcb has matching lcb */
|
||||
if (p_lcb->allocated && (!memcmp(p_lcb->peer_addr, bd_addr, BD_ADDR_LEN))) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i == AVCT_NUM_LINKS) {
|
||||
/* if no lcb found */
|
||||
p_lcb = NULL;
|
||||
|
||||
AVCT_TRACE_DEBUG("No lcb for addr %02x-%02x-%02x-%02x-%02x-%02x",
|
||||
bd_addr[0], bd_addr[1], bd_addr[2], bd_addr[3], bd_addr[4], bd_addr[5]);
|
||||
}
|
||||
return p_lcb;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function avct_lcb_alloc
|
||||
**
|
||||
** Description Allocate a link control block.
|
||||
**
|
||||
**
|
||||
** Returns pointer to the lcb, or NULL if none could be allocated.
|
||||
**
|
||||
*******************************************************************************/
|
||||
tAVCT_LCB *avct_lcb_alloc(BD_ADDR bd_addr)
|
||||
{
|
||||
tAVCT_LCB *p_lcb = &avct_cb.lcb[0];
|
||||
int i;
|
||||
|
||||
for (i = 0; i < AVCT_NUM_LINKS; i++, p_lcb++) {
|
||||
if (!p_lcb->allocated) {
|
||||
p_lcb->allocated = (UINT8)(i + 1);
|
||||
memcpy(p_lcb->peer_addr, bd_addr, BD_ADDR_LEN);
|
||||
AVCT_TRACE_DEBUG("avct_lcb_alloc %d", p_lcb->allocated);
|
||||
p_lcb->tx_q = fixed_queue_new(QUEUE_SIZE_MAX);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i == AVCT_NUM_LINKS) {
|
||||
/* out of lcbs */
|
||||
p_lcb = NULL;
|
||||
AVCT_TRACE_WARNING("Out of lcbs");
|
||||
}
|
||||
return p_lcb;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function avct_lcb_dealloc
|
||||
**
|
||||
** Description Deallocate a link control block.
|
||||
**
|
||||
**
|
||||
** Returns void.
|
||||
**
|
||||
*******************************************************************************/
|
||||
void avct_lcb_dealloc(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
|
||||
{
|
||||
UNUSED(p_data);
|
||||
|
||||
AVCT_TRACE_DEBUG("%s allocated: %d", __func__, p_lcb->allocated);
|
||||
|
||||
// Check if the LCB is still referenced
|
||||
|
||||
tAVCT_CCB *p_ccb = &avct_cb.ccb[0];
|
||||
for (size_t i = 0; i < AVCT_NUM_CONN; i++, p_ccb++)
|
||||
{
|
||||
if (p_ccb->allocated && p_ccb->p_lcb == p_lcb)
|
||||
{
|
||||
AVCT_TRACE_DEBUG("%s LCB in use; lcb index: %d", __func__, i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// If not, de-allocate now...
|
||||
|
||||
AVCT_TRACE_DEBUG("%s Freeing LCB", __func__);
|
||||
osi_free(p_lcb->p_rx_msg);
|
||||
fixed_queue_free(p_lcb->tx_q, NULL);
|
||||
memset(p_lcb, 0, sizeof(tAVCT_LCB));
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function avct_lcb_by_lcid
|
||||
**
|
||||
** Description Find the LCB associated with the L2CAP LCID
|
||||
**
|
||||
**
|
||||
** Returns pointer to the lcb, or NULL if none found.
|
||||
**
|
||||
*******************************************************************************/
|
||||
tAVCT_LCB *avct_lcb_by_lcid(UINT16 lcid)
|
||||
{
|
||||
tAVCT_LCB *p_lcb = &avct_cb.lcb[0];
|
||||
int i;
|
||||
|
||||
for (i = 0; i < AVCT_NUM_LINKS; i++, p_lcb++) {
|
||||
if (p_lcb->allocated && ((p_lcb->ch_lcid == lcid) || (p_lcb->conflict_lcid == lcid))) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i == AVCT_NUM_LINKS) {
|
||||
/* out of lcbs */
|
||||
p_lcb = NULL;
|
||||
AVCT_TRACE_WARNING("No lcb for lcid %x", lcid);
|
||||
}
|
||||
|
||||
return p_lcb;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function avct_lcb_has_pid
|
||||
**
|
||||
** Description See if any ccbs on this lcb have a particular pid.
|
||||
**
|
||||
**
|
||||
** Returns Pointer to CCB if PID found, NULL otherwise.
|
||||
**
|
||||
*******************************************************************************/
|
||||
tAVCT_CCB *avct_lcb_has_pid(tAVCT_LCB *p_lcb, UINT16 pid)
|
||||
{
|
||||
tAVCT_CCB *p_ccb = &avct_cb.ccb[0];
|
||||
int i;
|
||||
|
||||
for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++) {
|
||||
if (p_ccb->allocated && (p_ccb->p_lcb == p_lcb) && (p_ccb->cc.pid == pid)) {
|
||||
return p_ccb;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function avct_lcb_last_ccb
|
||||
**
|
||||
** Description See if given ccb is only one on the lcb.
|
||||
**
|
||||
**
|
||||
** Returns TRUE if ccb is last, FALSE otherwise.
|
||||
**
|
||||
*******************************************************************************/
|
||||
BOOLEAN avct_lcb_last_ccb(tAVCT_LCB *p_lcb, tAVCT_CCB *p_ccb_last)
|
||||
{
|
||||
tAVCT_CCB *p_ccb = &avct_cb.ccb[0];
|
||||
int i;
|
||||
|
||||
AVCT_TRACE_WARNING("avct_lcb_last_ccb");
|
||||
for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++) {
|
||||
AVCT_TRACE_WARNING("%x: aloc:%d, lcb:%p/%p, ccb:%p/%p",
|
||||
i, p_ccb->allocated, p_ccb->p_lcb, p_lcb, p_ccb, p_ccb_last);
|
||||
if (p_ccb->allocated && (p_ccb->p_lcb == p_lcb) && (p_ccb != p_ccb_last)) {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
#endif /* #if (defined(AVCT_INCLUDED) && AVCT_INCLUDED == TRUE) */
|
||||
@@ -0,0 +1,685 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* Copyright (C) 2003-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 module contains action functions of the link control state machine.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
#include <string.h>
|
||||
#include "stack/bt_types.h"
|
||||
#include "common/bt_target.h"
|
||||
#include "common/bt_defs.h"
|
||||
#include "stack/avct_api.h"
|
||||
#include "avct_int.h"
|
||||
#include "stack/btm_api.h"
|
||||
#include "osi/allocator.h"
|
||||
|
||||
#if (defined(AVCT_INCLUDED) && AVCT_INCLUDED == TRUE)
|
||||
|
||||
/* packet header length lookup table */
|
||||
const UINT8 avct_lcb_pkt_type_len[] = {
|
||||
AVCT_HDR_LEN_SINGLE,
|
||||
AVCT_HDR_LEN_START,
|
||||
AVCT_HDR_LEN_CONT,
|
||||
AVCT_HDR_LEN_END
|
||||
};
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function avct_lcb_msg_asmbl
|
||||
**
|
||||
** Description Reassemble incoming message.
|
||||
**
|
||||
**
|
||||
** Returns Pointer to reassembled message; NULL if no message
|
||||
** available.
|
||||
**
|
||||
*******************************************************************************/
|
||||
static BT_HDR *avct_lcb_msg_asmbl(tAVCT_LCB *p_lcb, BT_HDR *p_buf)
|
||||
{
|
||||
UINT8 *p;
|
||||
UINT8 pkt_type;
|
||||
BT_HDR *p_ret;
|
||||
UINT16 buf_len;
|
||||
|
||||
/* parse the message header */
|
||||
p = (UINT8 *)(p_buf + 1) + p_buf->offset;
|
||||
AVCT_PRS_PKT_TYPE(p, pkt_type);
|
||||
|
||||
/* quick sanity check on length */
|
||||
if (p_buf->len < avct_lcb_pkt_type_len[pkt_type]) {
|
||||
osi_free(p_buf);
|
||||
AVCT_TRACE_WARNING("Bad length during reassembly");
|
||||
p_ret = NULL;
|
||||
}
|
||||
/* single packet */
|
||||
else if (pkt_type == AVCT_PKT_TYPE_SINGLE) {
|
||||
/* if reassembly in progress drop message and process new single */
|
||||
if (p_lcb->p_rx_msg != NULL) {
|
||||
AVCT_TRACE_WARNING("Got single during reassembly");
|
||||
}
|
||||
osi_free(p_lcb->p_rx_msg);
|
||||
p_lcb->p_rx_msg = NULL;
|
||||
p_ret = p_buf;
|
||||
}
|
||||
/* start packet */
|
||||
else if (pkt_type == AVCT_PKT_TYPE_START) {
|
||||
/* if reassembly in progress drop message and process new start */
|
||||
if (p_lcb->p_rx_msg != NULL) {
|
||||
AVCT_TRACE_WARNING("Got start during reassembly");
|
||||
}
|
||||
osi_free(p_lcb->p_rx_msg);
|
||||
/* Allocate bigger buffer for reassembly. As lower layers are
|
||||
* not aware of possible packet size after reassembly they
|
||||
* would have allocated smaller buffer.
|
||||
*/
|
||||
p_lcb->p_rx_msg = (BT_HDR *)osi_malloc(BT_DEFAULT_BUFFER_SIZE);
|
||||
if (p_lcb->p_rx_msg == NULL) {
|
||||
AVCT_TRACE_ERROR ("Cannot alloc buffer for reassembly !!");
|
||||
osi_free(p_buf);
|
||||
} else {
|
||||
memcpy (p_lcb->p_rx_msg, p_buf,
|
||||
sizeof(BT_HDR) + p_buf->offset + p_buf->len);
|
||||
/* Free original buffer */
|
||||
osi_free(p_buf);
|
||||
|
||||
/* update p to point to new buffer */
|
||||
p = (UINT8 *)(p_lcb->p_rx_msg + 1) + p_lcb->p_rx_msg->offset;
|
||||
|
||||
/* copy first header byte over nosp */
|
||||
*(p + 1) = *p;
|
||||
|
||||
/* set offset to point to where to copy next */
|
||||
p_lcb->p_rx_msg->offset += p_lcb->p_rx_msg->len;
|
||||
|
||||
/* adjust length for packet header */
|
||||
p_lcb->p_rx_msg->len -= 1;
|
||||
}
|
||||
p_ret = NULL;
|
||||
}
|
||||
/* continue or end */
|
||||
else {
|
||||
/* if no reassembly in progress drop message */
|
||||
if (p_lcb->p_rx_msg == NULL) {
|
||||
osi_free(p_buf);
|
||||
AVCT_TRACE_WARNING("Pkt type=%d out of order", pkt_type);
|
||||
p_ret = NULL;
|
||||
} else {
|
||||
/* get size of buffer holding assembled message */
|
||||
/*
|
||||
* NOTE: The buffer is allocated above at the beginning of the
|
||||
* reassembly, and is always of size BT_DEFAULT_BUFFER_SIZE.
|
||||
*/
|
||||
buf_len = BT_DEFAULT_BUFFER_SIZE - sizeof(BT_HDR);
|
||||
|
||||
/* adjust offset and len of fragment for header byte */
|
||||
p_buf->offset += AVCT_HDR_LEN_CONT;
|
||||
p_buf->len -= AVCT_HDR_LEN_CONT;
|
||||
|
||||
/* verify length */
|
||||
if ((p_lcb->p_rx_msg->offset + p_buf->len) > buf_len) {
|
||||
/* won't fit; free everything */
|
||||
AVCT_TRACE_WARNING("%s: Fragmented message too big!", __func__);
|
||||
osi_free(p_lcb->p_rx_msg);
|
||||
p_lcb->p_rx_msg = NULL;
|
||||
osi_free(p_buf);
|
||||
p_ret = NULL;
|
||||
} else {
|
||||
/* copy contents of p_buf to p_rx_msg */
|
||||
memcpy((UINT8 *)(p_lcb->p_rx_msg + 1) + p_lcb->p_rx_msg->offset,
|
||||
(UINT8 *)(p_buf + 1) + p_buf->offset, p_buf->len);
|
||||
|
||||
if (pkt_type == AVCT_PKT_TYPE_END) {
|
||||
p_lcb->p_rx_msg->offset -= p_lcb->p_rx_msg->len;
|
||||
p_lcb->p_rx_msg->len += p_buf->len;
|
||||
p_ret = p_lcb->p_rx_msg;
|
||||
p_lcb->p_rx_msg = NULL;
|
||||
} else {
|
||||
p_lcb->p_rx_msg->offset += p_buf->len;
|
||||
p_lcb->p_rx_msg->len += p_buf->len;
|
||||
p_ret = NULL;
|
||||
}
|
||||
osi_free(p_buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
return p_ret;
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function avct_lcb_chnl_open
|
||||
**
|
||||
** Description Open L2CAP channel to peer
|
||||
**
|
||||
**
|
||||
** Returns Nothing.
|
||||
**
|
||||
*******************************************************************************/
|
||||
void avct_lcb_chnl_open(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
|
||||
{
|
||||
UINT16 result = AVCT_RESULT_FAIL;
|
||||
UNUSED(p_data);
|
||||
|
||||
BTM_SetOutService(p_lcb->peer_addr, BTM_SEC_SERVICE_AVCTP, 0);
|
||||
/* call l2cap connect req */
|
||||
p_lcb->ch_state = AVCT_CH_CONN;
|
||||
if ((p_lcb->ch_lcid = L2CA_ConnectReq(AVCT_PSM, p_lcb->peer_addr)) == 0) {
|
||||
/* if connect req failed, send ourselves close event */
|
||||
avct_lcb_event(p_lcb, AVCT_LCB_LL_CLOSE_EVT, (tAVCT_LCB_EVT *) &result);
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function avct_lcb_unbind_disc
|
||||
**
|
||||
** Description Deallocate ccb and call callback with disconnect event.
|
||||
**
|
||||
**
|
||||
** Returns Nothing.
|
||||
**
|
||||
*******************************************************************************/
|
||||
void avct_lcb_unbind_disc(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
|
||||
{
|
||||
UNUSED(p_lcb);
|
||||
|
||||
avct_ccb_dealloc(p_data->p_ccb, AVCT_DISCONNECT_CFM_EVT, 0, NULL);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function avct_lcb_open_ind
|
||||
**
|
||||
** Description Handle an LL_OPEN event. For each allocated ccb already
|
||||
** bound to this lcb, send a connect event. For each
|
||||
** unbound ccb with a new PID, bind that ccb to this lcb and
|
||||
** send a connect event.
|
||||
**
|
||||
**
|
||||
** Returns Nothing.
|
||||
**
|
||||
*******************************************************************************/
|
||||
void avct_lcb_open_ind(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
|
||||
{
|
||||
tAVCT_CCB *p_ccb = &avct_cb.ccb[0];
|
||||
int i;
|
||||
BOOLEAN bind = FALSE;
|
||||
|
||||
for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++) {
|
||||
/* if ccb allocated and */
|
||||
if (p_ccb->allocated) {
|
||||
/* if bound to this lcb send connect confirm event */
|
||||
if (p_ccb->p_lcb == p_lcb) {
|
||||
bind = TRUE;
|
||||
L2CA_SetTxPriority(p_lcb->ch_lcid, L2CAP_CHNL_PRIORITY_HIGH);
|
||||
p_ccb->cc.p_ctrl_cback(avct_ccb_to_idx(p_ccb), AVCT_CONNECT_CFM_EVT,
|
||||
0, p_lcb->peer_addr);
|
||||
}
|
||||
/* if unbound acceptor and lcb doesn't already have a ccb for this PID */
|
||||
else if ((p_ccb->p_lcb == NULL) && (p_ccb->cc.role == AVCT_ACP) &&
|
||||
(avct_lcb_has_pid(p_lcb, p_ccb->cc.pid) == NULL)) {
|
||||
/* bind ccb to lcb and send connect ind event */
|
||||
bind = TRUE;
|
||||
p_ccb->p_lcb = p_lcb;
|
||||
L2CA_SetTxPriority(p_lcb->ch_lcid, L2CAP_CHNL_PRIORITY_HIGH);
|
||||
p_ccb->cc.p_ctrl_cback(avct_ccb_to_idx(p_ccb), AVCT_CONNECT_IND_EVT,
|
||||
0, p_lcb->peer_addr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* if no ccbs bound to this lcb, disconnect */
|
||||
if (bind == FALSE) {
|
||||
avct_lcb_event(p_lcb, AVCT_LCB_INT_CLOSE_EVT, p_data);
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function avct_lcb_open_fail
|
||||
**
|
||||
** Description L2CAP channel open attempt failed. Deallocate any ccbs
|
||||
** on this lcb and send connect confirm event with failure.
|
||||
**
|
||||
**
|
||||
** Returns Nothing.
|
||||
**
|
||||
*******************************************************************************/
|
||||
void avct_lcb_open_fail(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
|
||||
{
|
||||
tAVCT_CCB *p_ccb = &avct_cb.ccb[0];
|
||||
int i;
|
||||
|
||||
for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++) {
|
||||
if (p_ccb->allocated && (p_ccb->p_lcb == p_lcb)) {
|
||||
avct_ccb_dealloc(p_ccb, AVCT_CONNECT_CFM_EVT,
|
||||
p_data->result, p_lcb->peer_addr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function avct_lcb_close_ind
|
||||
**
|
||||
** Description L2CAP channel closed by peer. Deallocate any initiator
|
||||
** ccbs on this lcb and send disconnect ind event.
|
||||
**
|
||||
**
|
||||
** Returns Nothing.
|
||||
**
|
||||
*******************************************************************************/
|
||||
void avct_lcb_close_ind(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
|
||||
{
|
||||
tAVCT_CCB *p_ccb = &avct_cb.ccb[0];
|
||||
int i;
|
||||
UNUSED(p_data);
|
||||
|
||||
for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++) {
|
||||
if (p_ccb->allocated && (p_ccb->p_lcb == p_lcb)) {
|
||||
if (p_ccb->cc.role == AVCT_INT) {
|
||||
avct_ccb_dealloc(p_ccb, AVCT_DISCONNECT_IND_EVT,
|
||||
0, p_lcb->peer_addr);
|
||||
} else {
|
||||
p_ccb->p_lcb = NULL;
|
||||
(*p_ccb->cc.p_ctrl_cback)(avct_ccb_to_idx(p_ccb), AVCT_DISCONNECT_IND_EVT,
|
||||
0, p_lcb->peer_addr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function avct_lcb_close_cfm
|
||||
**
|
||||
** Description L2CAP channel closed by us. Deallocate any initiator
|
||||
** ccbs on this lcb and send disconnect ind or cfm event.
|
||||
**
|
||||
**
|
||||
** Returns Nothing.
|
||||
**
|
||||
*******************************************************************************/
|
||||
void avct_lcb_close_cfm(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
|
||||
{
|
||||
tAVCT_CCB *p_ccb = &avct_cb.ccb[0];
|
||||
int i;
|
||||
UINT8 event;
|
||||
|
||||
for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++) {
|
||||
if (p_ccb->allocated && (p_ccb->p_lcb == p_lcb)) {
|
||||
/* if this ccb initiated close send disconnect cfm otherwise ind */
|
||||
if (p_ccb->ch_close) {
|
||||
p_ccb->ch_close = FALSE;
|
||||
event = AVCT_DISCONNECT_CFM_EVT;
|
||||
} else {
|
||||
event = AVCT_DISCONNECT_IND_EVT;
|
||||
}
|
||||
|
||||
if (p_ccb->cc.role == AVCT_INT) {
|
||||
avct_ccb_dealloc(p_ccb, event, p_data->result, p_lcb->peer_addr);
|
||||
} else {
|
||||
p_ccb->p_lcb = NULL;
|
||||
(*p_ccb->cc.p_ctrl_cback)(avct_ccb_to_idx(p_ccb), event,
|
||||
p_data->result, p_lcb->peer_addr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function avct_lcb_bind_conn
|
||||
**
|
||||
** Description Bind ccb to lcb and send connect cfm event.
|
||||
**
|
||||
**
|
||||
** Returns Nothing.
|
||||
**
|
||||
*******************************************************************************/
|
||||
void avct_lcb_bind_conn(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
|
||||
{
|
||||
p_data->p_ccb->p_lcb = p_lcb;
|
||||
(*p_data->p_ccb->cc.p_ctrl_cback)(avct_ccb_to_idx(p_data->p_ccb),
|
||||
AVCT_CONNECT_CFM_EVT, 0, p_lcb->peer_addr);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function avct_lcb_chk_disc
|
||||
**
|
||||
** Description A ccb wants to close; if it is the last ccb on this lcb,
|
||||
** close channel. Otherwise just deallocate and call
|
||||
** callback.
|
||||
**
|
||||
**
|
||||
** Returns Nothing.
|
||||
**
|
||||
*******************************************************************************/
|
||||
void avct_lcb_chk_disc(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
|
||||
{
|
||||
AVCT_TRACE_EVENT("avct_lcb_chk_disc");
|
||||
#if (AVCT_BROWSE_INCLUDED == TRUE)
|
||||
avct_close_bcb(p_lcb, p_data);
|
||||
#endif
|
||||
if (avct_lcb_last_ccb(p_lcb, p_data->p_ccb)) {
|
||||
AVCT_TRACE_EVENT("closing");
|
||||
p_data->p_ccb->ch_close = TRUE;
|
||||
avct_lcb_event(p_lcb, AVCT_LCB_INT_CLOSE_EVT, p_data);
|
||||
} else {
|
||||
AVCT_TRACE_EVENT("dealloc ccb");
|
||||
avct_lcb_unbind_disc(p_lcb, p_data);
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function avct_lcb_chnl_disc
|
||||
**
|
||||
** Description Disconnect L2CAP channel.
|
||||
**
|
||||
**
|
||||
** Returns Nothing.
|
||||
**
|
||||
*******************************************************************************/
|
||||
void avct_lcb_chnl_disc(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
|
||||
{
|
||||
UNUSED(p_data);
|
||||
|
||||
L2CA_DisconnectReq(p_lcb->ch_lcid);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function avct_lcb_bind_fail
|
||||
**
|
||||
** Description Deallocate ccb and call callback with connect event
|
||||
** with failure result.
|
||||
**
|
||||
**
|
||||
** Returns Nothing.
|
||||
**
|
||||
*******************************************************************************/
|
||||
void avct_lcb_bind_fail(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
|
||||
{
|
||||
UNUSED(p_lcb);
|
||||
|
||||
avct_ccb_dealloc(p_data->p_ccb, AVCT_CONNECT_CFM_EVT, AVCT_RESULT_FAIL, NULL);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function avct_lcb_cong_ind
|
||||
**
|
||||
** Description Handle congestion indication from L2CAP.
|
||||
**
|
||||
**
|
||||
** Returns Nothing.
|
||||
**
|
||||
*******************************************************************************/
|
||||
void avct_lcb_cong_ind(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
|
||||
{
|
||||
tAVCT_CCB *p_ccb = &avct_cb.ccb[0];
|
||||
int i;
|
||||
UINT8 event;
|
||||
BT_HDR *p_buf;
|
||||
|
||||
/* set event */
|
||||
event = (p_data->cong) ? AVCT_CONG_IND_EVT : AVCT_UNCONG_IND_EVT;
|
||||
p_lcb->cong = p_data->cong;
|
||||
if (p_lcb->cong == FALSE && !fixed_queue_is_empty(p_lcb->tx_q))
|
||||
{
|
||||
while (!p_lcb->cong &&
|
||||
(p_buf = (BT_HDR *)fixed_queue_dequeue(p_lcb->tx_q, 0)) != NULL)
|
||||
{
|
||||
if (L2CA_DataWrite(p_lcb->ch_lcid, p_buf) == L2CAP_DW_CONGESTED)
|
||||
{
|
||||
p_lcb->cong = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* send event to all ccbs on this lcb */
|
||||
for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++) {
|
||||
if (p_ccb->allocated && (p_ccb->p_lcb == p_lcb)) {
|
||||
(*p_ccb->cc.p_ctrl_cback)(avct_ccb_to_idx(p_ccb), event, 0, p_lcb->peer_addr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function avct_lcb_discard_msg
|
||||
**
|
||||
** Description Discard a message sent in from the API.
|
||||
**
|
||||
**
|
||||
** Returns Nothing.
|
||||
**
|
||||
*******************************************************************************/
|
||||
void avct_lcb_discard_msg(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
|
||||
{
|
||||
UNUSED(p_lcb);
|
||||
|
||||
AVCT_TRACE_WARNING("Dropping msg");
|
||||
|
||||
osi_free(p_data->ul_msg.p_buf);
|
||||
p_data->ul_msg.p_buf = NULL;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function avct_lcb_send_msg
|
||||
**
|
||||
** Description Build and send an AVCTP message.
|
||||
**
|
||||
**
|
||||
** Returns Nothing.
|
||||
**
|
||||
*******************************************************************************/
|
||||
void avct_lcb_send_msg(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
|
||||
{
|
||||
UINT16 curr_msg_len;
|
||||
UINT8 pkt_type;
|
||||
UINT8 hdr_len;
|
||||
UINT8 *p;
|
||||
UINT8 nosp = 0; /* number of subsequent packets */
|
||||
UINT16 temp;
|
||||
UINT16 buf_size = p_lcb->peer_mtu + L2CAP_MIN_OFFSET + BT_HDR_SIZE;
|
||||
|
||||
|
||||
/* store msg len */
|
||||
curr_msg_len = p_data->ul_msg.p_buf->len;
|
||||
|
||||
/* initialize packet type and other stuff */
|
||||
if (curr_msg_len <= (p_lcb->peer_mtu - AVCT_HDR_LEN_SINGLE)) {
|
||||
pkt_type = AVCT_PKT_TYPE_SINGLE;
|
||||
} else {
|
||||
pkt_type = AVCT_PKT_TYPE_START;
|
||||
temp = (curr_msg_len + AVCT_HDR_LEN_START - p_lcb->peer_mtu);
|
||||
nosp = temp / (p_lcb->peer_mtu - 1) + 1;
|
||||
if ( (temp % (p_lcb->peer_mtu - 1)) != 0) {
|
||||
nosp++;
|
||||
}
|
||||
}
|
||||
|
||||
/* while we haven't sent all packets */
|
||||
while (curr_msg_len != 0) {
|
||||
BT_HDR *p_buf;
|
||||
|
||||
/* set header len */
|
||||
hdr_len = avct_lcb_pkt_type_len[pkt_type];
|
||||
|
||||
/* if remaining msg must be fragmented */
|
||||
if (p_data->ul_msg.p_buf->len > (p_lcb->peer_mtu - hdr_len)) {
|
||||
/* get a new buffer for fragment we are sending */
|
||||
if ((p_buf = (BT_HDR *) osi_malloc(buf_size)) == NULL) {
|
||||
/* whoops; free original msg buf and bail */
|
||||
AVCT_TRACE_ERROR ("avct_lcb_send_msg cannot alloc buffer!!");
|
||||
osi_free(p_data->ul_msg.p_buf);
|
||||
break;
|
||||
}
|
||||
|
||||
/* copy portion of data from current message to new buffer */
|
||||
p_buf->offset = L2CAP_MIN_OFFSET + hdr_len;
|
||||
p_buf->len = p_lcb->peer_mtu - hdr_len;
|
||||
|
||||
memcpy((UINT8 *)(p_buf + 1) + p_buf->offset,
|
||||
(UINT8 *)(p_data->ul_msg.p_buf + 1) + p_data->ul_msg.p_buf->offset, p_buf->len);
|
||||
|
||||
p_data->ul_msg.p_buf->offset += p_buf->len;
|
||||
p_data->ul_msg.p_buf->len -= p_buf->len;
|
||||
} else {
|
||||
p_buf = p_data->ul_msg.p_buf;
|
||||
}
|
||||
|
||||
curr_msg_len -= p_buf->len;
|
||||
|
||||
/* set up to build header */
|
||||
p_buf->len += hdr_len;
|
||||
p_buf->offset -= hdr_len;
|
||||
p = (UINT8 *)(p_buf + 1) + p_buf->offset;
|
||||
|
||||
/* build header */
|
||||
AVCT_BLD_HDR(p, p_data->ul_msg.label, pkt_type, p_data->ul_msg.cr);
|
||||
if (pkt_type == AVCT_PKT_TYPE_START) {
|
||||
UINT8_TO_STREAM(p, nosp);
|
||||
}
|
||||
if ((pkt_type == AVCT_PKT_TYPE_START) || (pkt_type == AVCT_PKT_TYPE_SINGLE)) {
|
||||
UINT16_TO_BE_STREAM(p, p_data->ul_msg.p_ccb->cc.pid);
|
||||
}
|
||||
|
||||
if (p_lcb->cong == TRUE) {
|
||||
fixed_queue_enqueue(p_lcb->tx_q, p_buf, FIXED_QUEUE_MAX_TIMEOUT);
|
||||
}
|
||||
|
||||
/* send message to L2CAP */
|
||||
else {
|
||||
if (L2CA_DataWrite(p_lcb->ch_lcid, p_buf) == L2CAP_DW_CONGESTED) {
|
||||
p_lcb->cong = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/* update pkt type for next packet */
|
||||
if (curr_msg_len > (p_lcb->peer_mtu - AVCT_HDR_LEN_END)) {
|
||||
pkt_type = AVCT_PKT_TYPE_CONT;
|
||||
} else {
|
||||
pkt_type = AVCT_PKT_TYPE_END;
|
||||
}
|
||||
}
|
||||
AVCT_TRACE_DEBUG ("avct_lcb_send_msg tx_q_count:%d",
|
||||
fixed_queue_length(p_lcb->tx_q));
|
||||
return;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function avct_lcb_free_msg_ind
|
||||
**
|
||||
** Description Discard an incoming AVCTP message.
|
||||
**
|
||||
**
|
||||
** Returns Nothing.
|
||||
**
|
||||
*******************************************************************************/
|
||||
void avct_lcb_free_msg_ind(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
|
||||
{
|
||||
UNUSED(p_lcb);
|
||||
|
||||
if (p_data == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
osi_free(p_data->p_buf);
|
||||
p_data->p_buf = NULL;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Function avct_lcb_msg_ind
|
||||
**
|
||||
** Description Handle an incoming AVCTP message.
|
||||
**
|
||||
**
|
||||
** Returns Nothing.
|
||||
**
|
||||
*******************************************************************************/
|
||||
void avct_lcb_msg_ind(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data)
|
||||
{
|
||||
UINT8 *p;
|
||||
UINT8 label, type, cr_ipid;
|
||||
UINT16 pid;
|
||||
tAVCT_CCB *p_ccb;
|
||||
BT_HDR *p_buf;
|
||||
|
||||
/* this p_buf is to be reported through p_msg_cback. The layer_specific
|
||||
* needs to be set properly to indicate that it is received through
|
||||
* control channel */
|
||||
p_data->p_buf->layer_specific = AVCT_DATA_CTRL;
|
||||
|
||||
/* reassemble message; if no message available (we received a fragment) return */
|
||||
if ((p_data->p_buf = avct_lcb_msg_asmbl(p_lcb, p_data->p_buf)) == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
p = (UINT8 *)(p_data->p_buf + 1) + p_data->p_buf->offset;
|
||||
|
||||
/* parse header byte */
|
||||
AVCT_PRS_HDR(p, label, type, cr_ipid);
|
||||
UNUSED(type);
|
||||
|
||||
/* check for invalid cr_ipid */
|
||||
if (cr_ipid == AVCT_CR_IPID_INVALID) {
|
||||
AVCT_TRACE_WARNING("Invalid cr_ipid %d", cr_ipid);
|
||||
osi_free(p_data->p_buf);
|
||||
p_data->p_buf = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
/* parse and lookup PID */
|
||||
BE_STREAM_TO_UINT16(pid, p);
|
||||
if ((p_ccb = avct_lcb_has_pid(p_lcb, pid)) != NULL) {
|
||||
/* PID found; send msg up, adjust bt hdr and call msg callback */
|
||||
p_data->p_buf->offset += AVCT_HDR_LEN_SINGLE;
|
||||
p_data->p_buf->len -= AVCT_HDR_LEN_SINGLE;
|
||||
(*p_ccb->cc.p_msg_cback)(avct_ccb_to_idx(p_ccb), label, cr_ipid, p_data->p_buf);
|
||||
} else {
|
||||
/* PID not found; drop message */
|
||||
AVCT_TRACE_WARNING("No ccb for PID=%x", pid);
|
||||
osi_free(p_data->p_buf);
|
||||
p_data->p_buf = NULL;
|
||||
|
||||
/* if command send reject */
|
||||
if (cr_ipid == AVCT_CMD) {
|
||||
if ((p_buf = (BT_HDR *) osi_malloc(AVCT_CMD_BUF_SIZE)) != NULL) {
|
||||
p_buf->len = AVCT_HDR_LEN_SINGLE;
|
||||
p_buf->offset = AVCT_MSG_OFFSET - AVCT_HDR_LEN_SINGLE;
|
||||
p = (UINT8 *)(p_buf + 1) + p_buf->offset;
|
||||
AVCT_BLD_HDR(p, label, AVCT_PKT_TYPE_SINGLE, AVCT_REJ);
|
||||
UINT16_TO_BE_STREAM(p, pid);
|
||||
L2CA_DataWrite(p_lcb->ch_lcid, p_buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* #if (defined(AVCT_INCLUDED) && AVCT_INCLUDED == TRUE) */
|
||||
@@ -0,0 +1,62 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* Copyright (C) 2003-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 contains constants definitions and other information from the AVCTP
|
||||
* specification. This file is intended for use internal to AVCT only.
|
||||
*
|
||||
******************************************************************************/
|
||||
#ifndef AVCT_DEFS_H
|
||||
#define AVCT_DEFS_H
|
||||
|
||||
/*****************************************************************************
|
||||
** constants
|
||||
*****************************************************************************/
|
||||
|
||||
/* packet type */
|
||||
#define AVCT_PKT_TYPE_SINGLE 0 /* single packet */
|
||||
#define AVCT_PKT_TYPE_START 1 /* start packet */
|
||||
#define AVCT_PKT_TYPE_CONT 2 /* continue packet */
|
||||
#define AVCT_PKT_TYPE_END 3 /* end packet */
|
||||
|
||||
/* header lengths for different packet types */
|
||||
#define AVCT_HDR_LEN_SINGLE 3
|
||||
#define AVCT_HDR_LEN_START 4
|
||||
#define AVCT_HDR_LEN_CONT 1
|
||||
#define AVCT_HDR_LEN_END 1
|
||||
|
||||
/* invalid cr+ipid value */
|
||||
#define AVCT_CR_IPID_INVALID 1
|
||||
|
||||
/*****************************************************************************
|
||||
** message parsing and building macros
|
||||
*****************************************************************************/
|
||||
|
||||
#define AVCT_BLD_HDR(p, label, type, cr_ipid) \
|
||||
*(p)++ = ((label) << 4) | ((type) << 2) | (cr_ipid);
|
||||
|
||||
#define AVCT_PRS_HDR(p, label, type, cr_ipid) \
|
||||
label = *(p) >> 4; \
|
||||
type = (*(p) >> 2) & 3; \
|
||||
cr_ipid = *(p)++ & 3;
|
||||
|
||||
#define AVCT_PRS_PKT_TYPE(p, type) \
|
||||
type = (*(p) >> 2) & 3;
|
||||
|
||||
#endif /* AVCT_DEFS_H */
|
||||
@@ -0,0 +1,237 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* Copyright (C) 2003-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 interfaces which are internal to AVCTP.
|
||||
*
|
||||
******************************************************************************/
|
||||
#ifndef AVCT_INT_H
|
||||
#define AVCT_INT_H
|
||||
|
||||
#include "stack/avct_api.h"
|
||||
#include "avct_defs.h"
|
||||
#include "stack/l2c_api.h"
|
||||
#include "osi/fixed_queue.h"
|
||||
|
||||
/*****************************************************************************
|
||||
** constants
|
||||
*****************************************************************************/
|
||||
|
||||
/* lcb state machine events */
|
||||
enum {
|
||||
AVCT_LCB_UL_BIND_EVT,
|
||||
AVCT_LCB_UL_UNBIND_EVT,
|
||||
AVCT_LCB_UL_MSG_EVT,
|
||||
AVCT_LCB_INT_CLOSE_EVT,
|
||||
AVCT_LCB_LL_OPEN_EVT,
|
||||
AVCT_LCB_LL_CLOSE_EVT,
|
||||
AVCT_LCB_LL_MSG_EVT,
|
||||
AVCT_LCB_LL_CONG_EVT
|
||||
};
|
||||
|
||||
|
||||
/* "states" used for L2CAP channel */
|
||||
#define AVCT_CH_IDLE 0 /* No connection */
|
||||
#define AVCT_CH_CONN 1 /* Waiting for connection confirm */
|
||||
#define AVCT_CH_CFG 2 /* Waiting for configuration complete */
|
||||
#define AVCT_CH_OPEN 3 /* Channel opened */
|
||||
|
||||
/* "no event" indicator used by ccb dealloc */
|
||||
#define AVCT_NO_EVT 0xFF
|
||||
|
||||
/*****************************************************************************
|
||||
** data types
|
||||
*****************************************************************************/
|
||||
/* sub control block type - common data members for tAVCT_LCB and tAVCT_BCB */
|
||||
typedef struct {
|
||||
UINT16 peer_mtu; /* peer l2c mtu */
|
||||
UINT16 ch_result; /* L2CAP connection result value */
|
||||
UINT16 ch_lcid; /* L2CAP channel LCID */
|
||||
UINT8 allocated; /* 0, not allocated. index+1, otherwise. */
|
||||
UINT8 state; /* The state machine state */
|
||||
UINT8 ch_state; /* L2CAP channel state */
|
||||
UINT8 ch_flags; /* L2CAP configuration flags */
|
||||
} tAVCT_SCB;
|
||||
|
||||
/* link control block type */
|
||||
typedef struct {
|
||||
UINT16 peer_mtu; /* peer l2c mtu */
|
||||
UINT16 ch_result; /* L2CAP connection result value */
|
||||
UINT16 ch_lcid; /* L2CAP channel LCID */
|
||||
UINT8 allocated; /* 0, not allocated. index+1, otherwise. */
|
||||
UINT8 state; /* The state machine state */
|
||||
UINT8 ch_state; /* L2CAP channel state */
|
||||
UINT8 ch_flags; /* L2CAP configuration flags */
|
||||
BT_HDR *p_rx_msg; /* Message being reassembled */
|
||||
UINT16 conflict_lcid; /* L2CAP channel LCID */
|
||||
BD_ADDR peer_addr; /* BD address of peer */
|
||||
fixed_queue_t *tx_q; /* Transmit data buffer queue */
|
||||
BOOLEAN cong; /* TRUE, if congested */
|
||||
} tAVCT_LCB;
|
||||
|
||||
/* browse control block type */
|
||||
typedef struct {
|
||||
UINT16 peer_mtu; /* peer l2c mtu */
|
||||
UINT16 ch_result; /* L2CAP connection result value */
|
||||
UINT16 ch_lcid; /* L2CAP channel LCID */
|
||||
UINT8 allocated; /* 0, not allocated. index+1, otherwise. */
|
||||
UINT8 state; /* The state machine state */
|
||||
UINT8 ch_state; /* L2CAP channel state */
|
||||
UINT8 ch_flags; /* L2CAP configuration flags */
|
||||
BT_HDR *p_tx_msg; /* Message to be sent - in case the browsing channel is not open when MsgReg is called */
|
||||
UINT8 ch_close; /* CCB index+1, if CCB initiated channel close */
|
||||
} tAVCT_BCB;
|
||||
|
||||
#define AVCT_ALOC_LCB 0x01
|
||||
#define AVCT_ALOC_BCB 0x02
|
||||
/* connection control block */
|
||||
typedef struct {
|
||||
tAVCT_CC cc; /* parameters from connection creation */
|
||||
tAVCT_LCB *p_lcb; /* Associated LCB */
|
||||
tAVCT_BCB *p_bcb; /* associated BCB */
|
||||
BOOLEAN ch_close; /* Whether CCB initiated channel close */
|
||||
UINT8 allocated; /* Whether LCB/BCB is allocated */
|
||||
} tAVCT_CCB;
|
||||
|
||||
/* data type associated with UL_MSG_EVT */
|
||||
typedef struct {
|
||||
BT_HDR *p_buf;
|
||||
tAVCT_CCB *p_ccb;
|
||||
UINT8 label;
|
||||
UINT8 cr;
|
||||
} tAVCT_UL_MSG;
|
||||
|
||||
/* union associated with lcb state machine events */
|
||||
typedef union {
|
||||
tAVCT_UL_MSG ul_msg;
|
||||
BT_HDR *p_buf;
|
||||
tAVCT_CCB *p_ccb;
|
||||
UINT16 result;
|
||||
BOOLEAN cong;
|
||||
UINT8 err_code;
|
||||
} tAVCT_LCB_EVT;
|
||||
|
||||
/* Control block for AVCT */
|
||||
typedef struct {
|
||||
tAVCT_LCB lcb[AVCT_NUM_LINKS]; /* link control blocks */
|
||||
tAVCT_BCB bcb[AVCT_NUM_LINKS]; /* browse control blocks */
|
||||
tAVCT_CCB ccb[AVCT_NUM_CONN]; /* connection control blocks */
|
||||
UINT16 mtu; /* our L2CAP MTU */
|
||||
UINT16 mtu_br; /* our L2CAP MTU for the Browsing channel */
|
||||
UINT8 trace_level; /* trace level */
|
||||
} tAVCT_CB;
|
||||
|
||||
/*****************************************************************************
|
||||
** function declarations
|
||||
*****************************************************************************/
|
||||
|
||||
/* LCB function declarations */
|
||||
extern void avct_lcb_event(tAVCT_LCB *p_lcb, UINT8 event, tAVCT_LCB_EVT *p_data);
|
||||
#if (AVCT_BROWSE_INCLUDED == TRUE)
|
||||
extern void avct_bcb_event(tAVCT_BCB *p_bcb, UINT8 event, tAVCT_LCB_EVT *p_data);
|
||||
extern void avct_close_bcb(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data);
|
||||
extern tAVCT_LCB *avct_lcb_by_bcb(tAVCT_BCB *p_bcb);
|
||||
extern tAVCT_BCB *avct_bcb_by_lcb(tAVCT_LCB *p_lcb);
|
||||
extern BOOLEAN avct_bcb_last_ccb(tAVCT_BCB *p_bcb, tAVCT_CCB *p_ccb_last);
|
||||
extern tAVCT_BCB *avct_bcb_by_lcid(UINT16 lcid);
|
||||
#endif
|
||||
extern tAVCT_LCB *avct_lcb_by_bd(BD_ADDR bd_addr);
|
||||
extern tAVCT_LCB *avct_lcb_alloc(BD_ADDR bd_addr);
|
||||
extern void avct_lcb_dealloc(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data);
|
||||
extern tAVCT_LCB *avct_lcb_by_lcid(UINT16 lcid);
|
||||
extern tAVCT_CCB *avct_lcb_has_pid(tAVCT_LCB *p_lcb, UINT16 pid);
|
||||
extern BOOLEAN avct_lcb_last_ccb(tAVCT_LCB *p_lcb, tAVCT_CCB *p_ccb_last);
|
||||
|
||||
/* LCB action functions */
|
||||
extern void avct_lcb_chnl_open(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data);
|
||||
extern void avct_lcb_unbind_disc(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data);
|
||||
extern void avct_lcb_open_ind(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data);
|
||||
extern void avct_lcb_open_fail(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data);
|
||||
extern void avct_lcb_close_ind(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data);
|
||||
extern void avct_lcb_close_cfm(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data);
|
||||
extern void avct_lcb_bind_conn(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data);
|
||||
extern void avct_lcb_chk_disc(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data);
|
||||
extern void avct_lcb_chnl_disc(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data);
|
||||
extern void avct_lcb_bind_fail(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data);
|
||||
extern void avct_lcb_cong_ind(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data);
|
||||
extern void avct_lcb_discard_msg(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data);
|
||||
extern void avct_lcb_send_msg(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data);
|
||||
extern void avct_lcb_msg_ind(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data);
|
||||
extern void avct_lcb_free_msg_ind(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data);
|
||||
|
||||
/* BCB action functions */
|
||||
#if (AVCT_BROWSE_INCLUDED == TRUE)
|
||||
typedef void (*tAVCT_BCB_ACTION)(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data);
|
||||
extern void avct_bcb_chnl_open(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data);
|
||||
extern void avct_bcb_unbind_disc(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data);
|
||||
extern void avct_bcb_open_ind(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data);
|
||||
extern void avct_bcb_open_fail(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data);
|
||||
extern void avct_bcb_close_ind(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data);
|
||||
extern void avct_bcb_close_cfm(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data);
|
||||
extern void avct_bcb_bind_conn(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data);
|
||||
extern void avct_bcb_chk_disc(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data);
|
||||
extern void avct_bcb_chnl_disc(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data);
|
||||
extern void avct_bcb_bind_fail(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data);
|
||||
extern void avct_bcb_cong_ind(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data);
|
||||
extern void avct_bcb_discard_msg(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data);
|
||||
extern void avct_bcb_send_msg(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data);
|
||||
extern void avct_bcb_msg_ind(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data);
|
||||
extern void avct_bcb_free_msg_ind(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data);
|
||||
|
||||
extern void avct_bcb_dealloc(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data);
|
||||
|
||||
extern const tAVCT_BCB_ACTION avct_bcb_action[];
|
||||
extern const UINT8 avct_lcb_pkt_type_len[];
|
||||
extern const tL2CAP_FCR_OPTS avct_l2c_br_fcr_opts_def;
|
||||
#endif
|
||||
|
||||
/* CCB function declarations */
|
||||
extern tAVCT_CCB *avct_ccb_alloc(tAVCT_CC *p_cc);
|
||||
extern void avct_ccb_dealloc(tAVCT_CCB *p_ccb, UINT8 event, UINT16 result, BD_ADDR bd_addr);
|
||||
extern UINT8 avct_ccb_to_idx(tAVCT_CCB *p_ccb);
|
||||
extern tAVCT_CCB *avct_ccb_by_idx(UINT8 idx);
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
** global data
|
||||
*****************************************************************************/
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
/* Main control block */
|
||||
#if AVCT_DYNAMIC_MEMORY == FALSE
|
||||
extern tAVCT_CB avct_cb;
|
||||
#else
|
||||
extern tAVCT_CB *avct_cb_ptr;
|
||||
#define avct_cb (*avct_cb_ptr)
|
||||
#endif
|
||||
|
||||
/* L2CAP callback registration structure */
|
||||
extern const tL2CAP_APPL_INFO avct_l2c_appl;
|
||||
#if (AVCT_BROWSE_INCLUDED == TRUE)
|
||||
extern const tL2CAP_APPL_INFO avct_l2c_br_appl;
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* AVCT_INT_H */
|
||||
Reference in New Issue
Block a user