2016-11-02 09:42:26 +00:00
|
|
|
/******************************************************************************
|
|
|
|
*
|
|
|
|
* Copyright (C) 2002-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 AVDTP adaption layer.
|
|
|
|
*
|
|
|
|
******************************************************************************/
|
|
|
|
|
|
|
|
// #include <assert.h>
|
|
|
|
#include "bt_trace.h"
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
#include "bt_types.h"
|
|
|
|
#include "bt_target.h"
|
|
|
|
#include "bt_utils.h"
|
|
|
|
#include "avdt_api.h"
|
|
|
|
#include "avdtc_api.h"
|
|
|
|
#include "avdt_int.h"
|
|
|
|
#include "l2c_api.h"
|
|
|
|
#include "l2cdefs.h"
|
2017-08-17 13:13:45 +00:00
|
|
|
#include "allocator.h"
|
2016-11-02 09:42:26 +00:00
|
|
|
|
2017-03-17 07:08:47 +00:00
|
|
|
#if (defined(AVDT_INCLUDED) && AVDT_INCLUDED == TRUE)
|
2016-11-02 09:42:26 +00:00
|
|
|
/*******************************************************************************
|
|
|
|
**
|
|
|
|
** Function avdt_ad_type_to_tcid
|
|
|
|
**
|
|
|
|
** Description Derives the TCID from the channel type and SCB.
|
|
|
|
**
|
|
|
|
**
|
|
|
|
** Returns TCID value.
|
|
|
|
**
|
|
|
|
*******************************************************************************/
|
|
|
|
UINT8 avdt_ad_type_to_tcid(UINT8 type, tAVDT_SCB *p_scb)
|
|
|
|
{
|
|
|
|
UINT8 scb_idx;
|
|
|
|
|
2017-03-17 14:46:49 +00:00
|
|
|
if (type == AVDT_CHAN_SIG) {
|
2016-11-02 09:42:26 +00:00
|
|
|
return 0;
|
2017-03-17 14:46:49 +00:00
|
|
|
} else {
|
2016-11-02 09:42:26 +00:00
|
|
|
scb_idx = avdt_scb_to_hdl(p_scb) - 1;
|
|
|
|
/*
|
|
|
|
AVDT_TRACE_DEBUG("type: %d, tcid: %d", type, ((scb_idx * (AVDT_CHAN_NUM_TYPES - 1)) + type));
|
|
|
|
*/
|
|
|
|
return ((scb_idx * (AVDT_CHAN_NUM_TYPES - 1)) + type);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
|
|
**
|
|
|
|
** Function avdt_ad_tcid_to_type
|
|
|
|
**
|
|
|
|
** Description Derives the channel type from the TCID.
|
|
|
|
**
|
|
|
|
**
|
|
|
|
** Returns Channel type value.
|
|
|
|
**
|
|
|
|
*******************************************************************************/
|
|
|
|
static UINT8 avdt_ad_tcid_to_type(UINT8 tcid)
|
|
|
|
{
|
|
|
|
UINT8 type;
|
|
|
|
|
2017-03-17 14:46:49 +00:00
|
|
|
if (tcid == 0) {
|
2016-11-02 09:42:26 +00:00
|
|
|
type = AVDT_CHAN_SIG;
|
2017-03-17 14:46:49 +00:00
|
|
|
} else {
|
2016-11-02 09:42:26 +00:00
|
|
|
/* tcid translates to type based on number of channels, as follows:
|
|
|
|
** only media channel : tcid=1,2,3,4,5,6... type=1,1,1,1,1,1...
|
|
|
|
** media and report : tcid=1,2,3,4,5,6... type=1,2,1,2,1,2...
|
|
|
|
** media, report, recov : tcid=1,2,3,4,5,6... type=1,2,3,1,2,3...
|
|
|
|
*/
|
|
|
|
type = ((tcid + AVDT_CHAN_NUM_TYPES - 2) % (AVDT_CHAN_NUM_TYPES - 1)) + 1;
|
|
|
|
}
|
2016-11-16 03:05:55 +00:00
|
|
|
AVDT_TRACE_DEBUG("tcid: %d, type: %d\n", tcid, type);
|
2016-11-02 09:42:26 +00:00
|
|
|
return type;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
|
|
**
|
|
|
|
** Function avdt_ad_init
|
|
|
|
**
|
|
|
|
** Description Initialize adaption layer.
|
|
|
|
**
|
|
|
|
**
|
|
|
|
** Returns Nothing.
|
|
|
|
**
|
|
|
|
*******************************************************************************/
|
|
|
|
void avdt_ad_init(void)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
tAVDT_TC_TBL *p_tbl = avdt_cb.ad.tc_tbl;
|
|
|
|
memset(&avdt_cb.ad, 0, sizeof(tAVDT_AD));
|
|
|
|
|
|
|
|
/* make sure the peer_mtu is a valid value */
|
2017-03-17 14:46:49 +00:00
|
|
|
for (i = 0; i < AVDT_NUM_TC_TBL; i++, p_tbl++) {
|
2016-11-02 09:42:26 +00:00
|
|
|
p_tbl->peer_mtu = L2CAP_DEFAULT_MTU;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
|
|
**
|
|
|
|
** Function avdt_ad_tc_tbl_by_st
|
|
|
|
**
|
|
|
|
** Description Find adaption layer transport channel table entry matching
|
|
|
|
** the given state.
|
|
|
|
**
|
|
|
|
**
|
|
|
|
** Returns Pointer to matching entry. For control channel it returns
|
|
|
|
** the matching entry. For media or other it returns the
|
|
|
|
** first matching entry (there could be more than one).
|
|
|
|
**
|
|
|
|
*******************************************************************************/
|
|
|
|
tAVDT_TC_TBL *avdt_ad_tc_tbl_by_st(UINT8 type, tAVDT_CCB *p_ccb, UINT8 state)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
tAVDT_TC_TBL *p_tbl = avdt_cb.ad.tc_tbl;
|
|
|
|
UINT8 ccb_idx;
|
|
|
|
|
2017-03-17 14:46:49 +00:00
|
|
|
if (p_ccb == NULL) {
|
2016-11-02 09:42:26 +00:00
|
|
|
/* resending security req */
|
2017-03-17 14:46:49 +00:00
|
|
|
for (i = 0; i < AVDT_NUM_TC_TBL; i++, p_tbl++) {
|
2016-11-02 09:42:26 +00:00
|
|
|
/* must be AVDT_CHAN_SIG - tcid always zero */
|
|
|
|
if ((p_tbl->tcid == 0) &&
|
2017-03-17 14:46:49 +00:00
|
|
|
(p_tbl->state == state)) {
|
2016-11-02 09:42:26 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2017-03-17 14:46:49 +00:00
|
|
|
} else {
|
2016-11-02 09:42:26 +00:00
|
|
|
ccb_idx = avdt_ccb_to_idx(p_ccb);
|
|
|
|
|
2017-03-17 14:46:49 +00:00
|
|
|
for (i = 0; i < AVDT_NUM_TC_TBL; i++, p_tbl++) {
|
|
|
|
if (type == AVDT_CHAN_SIG) {
|
2016-11-02 09:42:26 +00:00
|
|
|
/* if control channel, tcid always zero */
|
|
|
|
if ((p_tbl->tcid == 0) &&
|
2017-03-17 14:46:49 +00:00
|
|
|
(p_tbl->ccb_idx == ccb_idx) &&
|
|
|
|
(p_tbl->state == state)) {
|
2016-11-02 09:42:26 +00:00
|
|
|
break;
|
|
|
|
}
|
2017-03-17 14:46:49 +00:00
|
|
|
} else {
|
2016-11-02 09:42:26 +00:00
|
|
|
/* if other channel, tcid is always > zero */
|
|
|
|
if ((p_tbl->tcid > 0) &&
|
2017-03-17 14:46:49 +00:00
|
|
|
(p_tbl->ccb_idx == ccb_idx) &&
|
|
|
|
(p_tbl->state == state)) {
|
2016-11-02 09:42:26 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* if nothing found return null */
|
2017-03-17 14:46:49 +00:00
|
|
|
if (i == AVDT_NUM_TC_TBL) {
|
2016-11-02 09:42:26 +00:00
|
|
|
p_tbl = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return p_tbl;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
|
|
**
|
|
|
|
** Function avdt_ad_tc_tbl_by_lcid
|
|
|
|
**
|
|
|
|
** Description Find adaption layer transport channel table entry by LCID.
|
|
|
|
**
|
|
|
|
**
|
|
|
|
** Returns Pointer to entry.
|
|
|
|
**
|
|
|
|
*******************************************************************************/
|
|
|
|
tAVDT_TC_TBL *avdt_ad_tc_tbl_by_lcid(UINT16 lcid)
|
|
|
|
{
|
|
|
|
UINT8 idx;
|
|
|
|
|
|
|
|
idx = avdt_cb.ad.lcid_tbl[lcid - L2CAP_BASE_APPL_CID];
|
|
|
|
|
2017-03-17 14:46:49 +00:00
|
|
|
if (idx < AVDT_NUM_TC_TBL) {
|
2016-11-02 09:42:26 +00:00
|
|
|
return &avdt_cb.ad.tc_tbl[idx];
|
2017-03-17 14:46:49 +00:00
|
|
|
} else {
|
2016-11-02 09:42:26 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
|
|
**
|
|
|
|
** Function avdt_ad_tc_tbl_by_type
|
|
|
|
**
|
|
|
|
** Description This function retrieves the transport channel table entry
|
|
|
|
** for a particular channel.
|
|
|
|
**
|
|
|
|
**
|
|
|
|
** Returns Pointer to transport channel table entry.
|
|
|
|
**
|
|
|
|
*******************************************************************************/
|
|
|
|
tAVDT_TC_TBL *avdt_ad_tc_tbl_by_type(UINT8 type, tAVDT_CCB *p_ccb, tAVDT_SCB *p_scb)
|
|
|
|
{
|
|
|
|
UINT8 tcid;
|
|
|
|
int i;
|
|
|
|
tAVDT_TC_TBL *p_tbl = avdt_cb.ad.tc_tbl;
|
|
|
|
UINT8 ccb_idx = avdt_ccb_to_idx(p_ccb);
|
|
|
|
|
|
|
|
/* get tcid from type, scb */
|
|
|
|
tcid = avdt_ad_type_to_tcid(type, p_scb);
|
|
|
|
|
2017-03-17 14:46:49 +00:00
|
|
|
for (i = 0; i < AVDT_NUM_TC_TBL; i++, p_tbl++) {
|
|
|
|
if ((p_tbl->tcid == tcid) && (p_tbl->ccb_idx == ccb_idx)) {
|
2016-11-02 09:42:26 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(i != AVDT_NUM_TC_TBL);
|
|
|
|
|
|
|
|
return p_tbl;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
|
|
**
|
|
|
|
** Function avdt_ad_tc_tbl_alloc
|
|
|
|
**
|
|
|
|
** Description Allocate an entry in the traffic channel table.
|
|
|
|
**
|
|
|
|
**
|
|
|
|
** Returns Pointer to entry.
|
|
|
|
**
|
|
|
|
*******************************************************************************/
|
|
|
|
tAVDT_TC_TBL *avdt_ad_tc_tbl_alloc(tAVDT_CCB *p_ccb)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
tAVDT_TC_TBL *p_tbl = avdt_cb.ad.tc_tbl;
|
|
|
|
|
|
|
|
/* find next free entry in tc table */
|
2017-03-17 14:46:49 +00:00
|
|
|
for (i = 0; i < AVDT_NUM_TC_TBL; i++, p_tbl++) {
|
|
|
|
if (p_tbl->state == AVDT_AD_ST_UNUSED) {
|
2016-11-02 09:42:26 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* sanity check */
|
|
|
|
assert(i != AVDT_NUM_TC_TBL);
|
|
|
|
|
|
|
|
|
|
|
|
/* initialize entry */
|
|
|
|
p_tbl->peer_mtu = L2CAP_DEFAULT_MTU;
|
|
|
|
p_tbl->cfg_flags = 0;
|
|
|
|
p_tbl->ccb_idx = avdt_ccb_to_idx(p_ccb);
|
|
|
|
p_tbl->state = AVDT_AD_ST_IDLE;
|
|
|
|
return p_tbl;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
|
|
**
|
|
|
|
** Function avdt_ad_tc_tbl_to_idx
|
|
|
|
**
|
|
|
|
** Description Convert a transport channel table entry to an index.
|
|
|
|
**
|
|
|
|
**
|
|
|
|
** Returns Index value.
|
|
|
|
**
|
|
|
|
*******************************************************************************/
|
|
|
|
UINT8 avdt_ad_tc_tbl_to_idx(tAVDT_TC_TBL *p_tbl)
|
|
|
|
{
|
2016-11-16 03:05:55 +00:00
|
|
|
AVDT_TRACE_DEBUG("avdt_ad_tc_tbl_to_idx: %d\n", (p_tbl - avdt_cb.ad.tc_tbl));
|
2016-11-02 09:42:26 +00:00
|
|
|
/* use array arithmetic to determine index */
|
|
|
|
return (UINT8) (p_tbl - avdt_cb.ad.tc_tbl);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
|
|
**
|
|
|
|
** Function avdt_ad_tc_close_ind
|
|
|
|
**
|
|
|
|
** Description This function is called by the L2CAP interface when the
|
|
|
|
** L2CAP channel is closed. It looks up the CCB or SCB for
|
|
|
|
** the channel and sends it a close event. The reason
|
|
|
|
** parameter is the same value passed by the L2CAP
|
|
|
|
** callback function.
|
|
|
|
**
|
|
|
|
**
|
|
|
|
** Returns Nothing.
|
|
|
|
**
|
|
|
|
*******************************************************************************/
|
|
|
|
void avdt_ad_tc_close_ind(tAVDT_TC_TBL *p_tbl, UINT16 reason)
|
|
|
|
{
|
|
|
|
tAVDT_CCB *p_ccb;
|
|
|
|
tAVDT_SCB *p_scb;
|
|
|
|
tAVDT_SCB_TC_CLOSE close;
|
2017-02-23 06:30:08 +00:00
|
|
|
// UNUSED(reason);
|
2016-11-02 09:42:26 +00:00
|
|
|
|
|
|
|
close.old_tc_state = p_tbl->state;
|
2017-03-17 14:46:49 +00:00
|
|
|
|
2016-11-02 09:42:26 +00:00
|
|
|
/* clear avdt_ad_tc_tbl entry */
|
|
|
|
p_tbl->state = AVDT_AD_ST_UNUSED;
|
|
|
|
p_tbl->cfg_flags = 0;
|
|
|
|
p_tbl->peer_mtu = L2CAP_DEFAULT_MTU;
|
|
|
|
|
2016-11-16 03:05:55 +00:00
|
|
|
AVDT_TRACE_DEBUG("avdt_ad_tc_close_ind tcid: %d, old: %d\n",
|
2017-03-17 14:46:49 +00:00
|
|
|
p_tbl->tcid, close.old_tc_state);
|
|
|
|
|
2016-11-02 09:42:26 +00:00
|
|
|
/* if signaling channel, notify ccb that channel open */
|
2017-03-17 14:46:49 +00:00
|
|
|
if (p_tbl->tcid == 0) {
|
2016-11-02 09:42:26 +00:00
|
|
|
p_ccb = avdt_ccb_by_idx(p_tbl->ccb_idx);
|
2017-02-23 06:30:08 +00:00
|
|
|
p_ccb->disc_rsn = (reason == AVDT_DISC_RSN_ABNORMAL) ? AVDT_DISC_RSN_ABNORMAL : AVDT_DISC_RSN_NORMAL;
|
2016-11-02 09:42:26 +00:00
|
|
|
avdt_ccb_event(p_ccb, AVDT_CCB_LL_CLOSE_EVT, NULL);
|
|
|
|
}
|
|
|
|
/* if media or other channel, notify scb that channel close */
|
2017-03-17 14:46:49 +00:00
|
|
|
else {
|
2016-11-02 09:42:26 +00:00
|
|
|
/* look up scb in stream routing table by ccb, tcid */
|
|
|
|
p_scb = avdt_scb_by_hdl(avdt_cb.ad.rt_tbl[p_tbl->ccb_idx][p_tbl->tcid].scb_hdl);
|
2017-03-17 14:46:49 +00:00
|
|
|
if (p_scb != NULL) {
|
2016-11-02 09:42:26 +00:00
|
|
|
close.tcid = p_tbl->tcid;
|
|
|
|
close.type = avdt_ad_tcid_to_type(p_tbl->tcid);
|
2017-02-23 06:30:08 +00:00
|
|
|
close.disc_rsn = (reason == AVDT_DISC_RSN_ABNORMAL) ? AVDT_DISC_RSN_ABNORMAL : AVDT_DISC_RSN_NORMAL;
|
2016-11-02 09:42:26 +00:00
|
|
|
avdt_scb_event(p_scb, AVDT_SCB_TC_CLOSE_EVT, (tAVDT_SCB_EVT *)&close);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
|
|
**
|
|
|
|
** Function avdt_ad_tc_open_ind
|
|
|
|
**
|
|
|
|
** Description This function is called by the L2CAP interface when
|
|
|
|
** the L2CAP channel is opened. It looks up the CCB or SCB
|
|
|
|
** for the channel and sends it an open event.
|
|
|
|
**
|
|
|
|
**
|
|
|
|
** Returns Nothing.
|
|
|
|
**
|
|
|
|
*******************************************************************************/
|
|
|
|
void avdt_ad_tc_open_ind(tAVDT_TC_TBL *p_tbl)
|
|
|
|
{
|
|
|
|
tAVDT_CCB *p_ccb;
|
|
|
|
tAVDT_SCB *p_scb;
|
|
|
|
tAVDT_OPEN open;
|
|
|
|
tAVDT_EVT_HDR evt;
|
|
|
|
|
|
|
|
p_tbl->state = AVDT_AD_ST_OPEN;
|
|
|
|
|
|
|
|
/* if signaling channel, notify ccb that channel open */
|
2017-03-17 14:46:49 +00:00
|
|
|
if (p_tbl->tcid == 0) {
|
2016-11-02 09:42:26 +00:00
|
|
|
/* set the signal channel to use high priority within the ACL link */
|
|
|
|
L2CA_SetTxPriority(avdt_cb.ad.rt_tbl[p_tbl->ccb_idx][AVDT_CHAN_SIG].lcid, L2CAP_CHNL_PRIORITY_HIGH);
|
|
|
|
|
|
|
|
p_ccb = avdt_ccb_by_idx(p_tbl->ccb_idx);
|
|
|
|
/* use err_param to indicate the role of connection.
|
|
|
|
* AVDT_ACP, if ACP */
|
|
|
|
evt.err_param = AVDT_INT;
|
2017-03-17 14:46:49 +00:00
|
|
|
if (p_tbl->cfg_flags & AVDT_L2C_CFG_CONN_ACP) {
|
2016-11-02 09:42:26 +00:00
|
|
|
evt.err_param = AVDT_ACP;
|
|
|
|
}
|
|
|
|
avdt_ccb_event(p_ccb, AVDT_CCB_LL_OPEN_EVT, (tAVDT_CCB_EVT *)&evt);
|
|
|
|
}
|
|
|
|
/* if media or other channel, notify scb that channel open */
|
2017-03-17 14:46:49 +00:00
|
|
|
else {
|
2016-11-02 09:42:26 +00:00
|
|
|
/* look up scb in stream routing table by ccb, tcid */
|
|
|
|
p_scb = avdt_scb_by_hdl(avdt_cb.ad.rt_tbl[p_tbl->ccb_idx][p_tbl->tcid].scb_hdl);
|
|
|
|
|
|
|
|
/* put lcid in event data */
|
2017-03-17 14:46:49 +00:00
|
|
|
if (p_scb != NULL) {
|
2016-11-02 09:42:26 +00:00
|
|
|
open.peer_mtu = p_tbl->peer_mtu;
|
|
|
|
open.lcid = avdt_cb.ad.rt_tbl[p_tbl->ccb_idx][p_tbl->tcid].lcid;
|
|
|
|
open.hdr.err_code = avdt_ad_tcid_to_type(p_tbl->tcid);
|
|
|
|
avdt_scb_event(p_scb, AVDT_SCB_TC_OPEN_EVT, (tAVDT_SCB_EVT *) &open);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
|
|
**
|
|
|
|
** Function avdt_ad_tc_cong_ind
|
|
|
|
**
|
|
|
|
** Description This function is called by the L2CAP interface layer when
|
|
|
|
** L2CAP calls the congestion callback. It looks up the CCB
|
|
|
|
** or SCB for the channel and sends it a congestion event.
|
|
|
|
** The is_congested parameter is the same value passed by
|
|
|
|
** the L2CAP callback function.
|
|
|
|
**
|
|
|
|
**
|
|
|
|
** Returns Nothing.
|
|
|
|
**
|
|
|
|
*******************************************************************************/
|
|
|
|
void avdt_ad_tc_cong_ind(tAVDT_TC_TBL *p_tbl, BOOLEAN is_congested)
|
|
|
|
{
|
|
|
|
tAVDT_CCB *p_ccb;
|
|
|
|
tAVDT_SCB *p_scb;
|
|
|
|
|
|
|
|
/* if signaling channel, notify ccb of congestion */
|
2017-03-17 14:46:49 +00:00
|
|
|
if (p_tbl->tcid == 0) {
|
2016-11-02 09:42:26 +00:00
|
|
|
p_ccb = avdt_ccb_by_idx(p_tbl->ccb_idx);
|
|
|
|
avdt_ccb_event(p_ccb, AVDT_CCB_LL_CONG_EVT, (tAVDT_CCB_EVT *) &is_congested);
|
|
|
|
}
|
|
|
|
/* if media or other channel, notify scb that channel open */
|
2017-03-17 14:46:49 +00:00
|
|
|
else {
|
2016-11-02 09:42:26 +00:00
|
|
|
/* look up scb in stream routing table by ccb, tcid */
|
|
|
|
p_scb = avdt_scb_by_hdl(avdt_cb.ad.rt_tbl[p_tbl->ccb_idx][p_tbl->tcid].scb_hdl);
|
2017-03-17 14:46:49 +00:00
|
|
|
if (p_scb != NULL) {
|
2016-11-02 09:42:26 +00:00
|
|
|
avdt_scb_event(p_scb, AVDT_SCB_TC_CONG_EVT, (tAVDT_SCB_EVT *) &is_congested);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
|
|
**
|
|
|
|
** Function avdt_ad_tc_data_ind
|
|
|
|
**
|
|
|
|
** Description This function is called by the L2CAP interface layer when
|
|
|
|
** incoming data is received from L2CAP. It looks up the CCB
|
|
|
|
** or SCB for the channel and routes the data accordingly.
|
|
|
|
**
|
|
|
|
**
|
|
|
|
** Returns Nothing.
|
|
|
|
**
|
|
|
|
*******************************************************************************/
|
|
|
|
void avdt_ad_tc_data_ind(tAVDT_TC_TBL *p_tbl, BT_HDR *p_buf)
|
|
|
|
{
|
|
|
|
tAVDT_CCB *p_ccb;
|
|
|
|
tAVDT_SCB *p_scb;
|
|
|
|
|
|
|
|
/* store type (media, recovery, reporting) */
|
|
|
|
p_buf->layer_specific = avdt_ad_tcid_to_type(p_tbl->tcid);
|
|
|
|
|
|
|
|
|
|
|
|
/* if signaling channel, handle control message */
|
2017-03-17 14:46:49 +00:00
|
|
|
if (p_tbl->tcid == 0) {
|
2016-11-02 09:42:26 +00:00
|
|
|
p_ccb = avdt_ccb_by_idx(p_tbl->ccb_idx);
|
|
|
|
avdt_msg_ind(p_ccb, p_buf);
|
|
|
|
}
|
|
|
|
/* if media or other channel, send event to scb */
|
2017-03-17 14:46:49 +00:00
|
|
|
else {
|
2016-11-02 09:42:26 +00:00
|
|
|
p_scb = avdt_scb_by_hdl(avdt_cb.ad.rt_tbl[p_tbl->ccb_idx][p_tbl->tcid].scb_hdl);
|
2017-03-17 14:46:49 +00:00
|
|
|
if (p_scb != NULL) {
|
2016-11-02 09:42:26 +00:00
|
|
|
avdt_scb_event(p_scb, AVDT_SCB_TC_DATA_EVT, (tAVDT_SCB_EVT *) &p_buf);
|
2017-03-17 14:46:49 +00:00
|
|
|
} else {
|
2017-08-17 13:13:45 +00:00
|
|
|
osi_free(p_buf);
|
2016-11-02 09:42:26 +00:00
|
|
|
AVDT_TRACE_ERROR(" avdt_ad_tc_data_ind buffer freed");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
|
|
**
|
|
|
|
** Function avdt_ad_write_req
|
|
|
|
**
|
|
|
|
** Description This function is called by a CCB or SCB to send data to a
|
|
|
|
** transport channel. It looks up the LCID of the channel
|
|
|
|
** based on the type, CCB, and SCB (if present). Then it
|
|
|
|
** passes the data to L2CA_DataWrite().
|
|
|
|
**
|
|
|
|
**
|
|
|
|
** Returns AVDT_AD_SUCCESS, if data accepted, else FALSE
|
|
|
|
** AVDT_AD_CONGESTED, if data accepted and the channel is congested
|
|
|
|
** AVDT_AD_FAILED, if error
|
|
|
|
**
|
|
|
|
*******************************************************************************/
|
|
|
|
UINT8 avdt_ad_write_req(UINT8 type, tAVDT_CCB *p_ccb, tAVDT_SCB *p_scb, BT_HDR *p_buf)
|
|
|
|
{
|
|
|
|
UINT8 tcid;
|
|
|
|
|
|
|
|
/* get tcid from type, scb */
|
|
|
|
tcid = avdt_ad_type_to_tcid(type, p_scb);
|
|
|
|
|
|
|
|
|
|
|
|
return L2CA_DataWrite(avdt_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][tcid].lcid, p_buf);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
|
|
**
|
|
|
|
** Function avdt_ad_open_req
|
|
|
|
**
|
|
|
|
** Description This function is called by a CCB or SCB to open a transport
|
|
|
|
** channel. This function allocates and initializes a
|
|
|
|
** transport channel table entry. The channel can be opened
|
|
|
|
** in two roles: as an initiator or acceptor. When opened
|
|
|
|
** as an initiator the function will start an L2CAP connection.
|
|
|
|
** When opened as an acceptor the function simply configures
|
|
|
|
** the table entry to listen for an incoming channel.
|
|
|
|
**
|
|
|
|
**
|
|
|
|
** Returns Nothing.
|
|
|
|
**
|
|
|
|
*******************************************************************************/
|
|
|
|
void avdt_ad_open_req(UINT8 type, tAVDT_CCB *p_ccb, tAVDT_SCB *p_scb, UINT8 role)
|
|
|
|
{
|
|
|
|
tAVDT_TC_TBL *p_tbl;
|
|
|
|
UINT16 lcid;
|
|
|
|
|
2017-03-17 14:46:49 +00:00
|
|
|
if ((p_tbl = avdt_ad_tc_tbl_alloc(p_ccb)) == NULL) {
|
2016-11-02 09:42:26 +00:00
|
|
|
AVDT_TRACE_ERROR("avdt_ad_open_req: Cannot allocate p_tbl");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
p_tbl->tcid = avdt_ad_type_to_tcid(type, p_scb);
|
2016-11-16 03:05:55 +00:00
|
|
|
AVDT_TRACE_DEBUG("avdt_ad_open_req: type: %d, role: %d, tcid:%d\n",
|
2017-03-17 14:46:49 +00:00
|
|
|
type, role, p_tbl->tcid);
|
2016-11-02 09:42:26 +00:00
|
|
|
|
2017-03-17 14:46:49 +00:00
|
|
|
if (type == AVDT_CHAN_SIG) {
|
2016-11-02 09:42:26 +00:00
|
|
|
/* if signaling, get mtu from registration control block */
|
|
|
|
p_tbl->my_mtu = avdt_cb.rcb.ctrl_mtu;
|
|
|
|
p_tbl->my_flush_to = L2CAP_DEFAULT_FLUSH_TO;
|
2017-03-17 14:46:49 +00:00
|
|
|
} else {
|
2016-11-02 09:42:26 +00:00
|
|
|
/* otherwise get mtu from scb */
|
|
|
|
p_tbl->my_mtu = p_scb->cs.mtu;
|
|
|
|
p_tbl->my_flush_to = p_scb->cs.flush_to;
|
|
|
|
|
|
|
|
/* also set scb_hdl in rt_tbl */
|
|
|
|
avdt_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][p_tbl->tcid].scb_hdl = avdt_scb_to_hdl(p_scb);
|
2016-11-16 03:05:55 +00:00
|
|
|
AVDT_TRACE_DEBUG("avdt_cb.ad.rt_tbl[%d][%d].scb_hdl = %d\n",
|
2017-03-17 14:46:49 +00:00
|
|
|
avdt_ccb_to_idx(p_ccb), p_tbl->tcid,
|
|
|
|
avdt_scb_to_hdl(p_scb));
|
2016-11-02 09:42:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* if we're acceptor, we're done; just sit back and listen */
|
2017-03-17 14:46:49 +00:00
|
|
|
if (role == AVDT_ACP) {
|
2016-11-02 09:42:26 +00:00
|
|
|
p_tbl->state = AVDT_AD_ST_ACP;
|
|
|
|
}
|
|
|
|
/* else we're inititator, start the L2CAP connection */
|
2017-03-17 14:46:49 +00:00
|
|
|
else {
|
2016-11-02 09:42:26 +00:00
|
|
|
p_tbl->state = AVDT_AD_ST_CONN;
|
|
|
|
|
|
|
|
/* call l2cap connect req */
|
2017-03-17 14:46:49 +00:00
|
|
|
if ((lcid = L2CA_ConnectReq(AVDT_PSM, p_ccb->peer_addr)) != 0) {
|
2016-11-02 09:42:26 +00:00
|
|
|
/* if connect req ok, store tcid in lcid table */
|
|
|
|
avdt_cb.ad.lcid_tbl[lcid - L2CAP_BASE_APPL_CID] = avdt_ad_tc_tbl_to_idx(p_tbl);
|
2016-11-16 03:05:55 +00:00
|
|
|
AVDT_TRACE_DEBUG("avdt_cb.ad.lcid_tbl[%d] = %d\n",
|
2017-03-17 14:46:49 +00:00
|
|
|
(lcid - L2CAP_BASE_APPL_CID), avdt_ad_tc_tbl_to_idx(p_tbl));
|
2016-11-02 09:42:26 +00:00
|
|
|
|
|
|
|
avdt_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][p_tbl->tcid].lcid = lcid;
|
2016-11-16 03:05:55 +00:00
|
|
|
AVDT_TRACE_DEBUG("avdt_cb.ad.rt_tbl[%d][%d].lcid = 0x%x\n",
|
2017-03-17 14:46:49 +00:00
|
|
|
avdt_ccb_to_idx(p_ccb), p_tbl->tcid,
|
|
|
|
lcid);
|
|
|
|
} else {
|
2016-11-02 09:42:26 +00:00
|
|
|
/* if connect req failed, call avdt_ad_tc_close_ind() */
|
|
|
|
avdt_ad_tc_close_ind(p_tbl, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
|
|
**
|
|
|
|
** Function avdt_ad_close_req
|
|
|
|
**
|
|
|
|
** Description This function is called by a CCB or SCB to close a
|
|
|
|
** transport channel. The function looks up the LCID for the
|
|
|
|
** channel and calls L2CA_DisconnectReq().
|
|
|
|
**
|
|
|
|
**
|
|
|
|
** Returns Nothing.
|
|
|
|
**
|
|
|
|
*******************************************************************************/
|
|
|
|
void avdt_ad_close_req(UINT8 type, tAVDT_CCB *p_ccb, tAVDT_SCB *p_scb)
|
|
|
|
{
|
|
|
|
UINT8 tcid;
|
|
|
|
tAVDT_TC_TBL *p_tbl;
|
|
|
|
|
|
|
|
p_tbl = avdt_ad_tc_tbl_by_type(type, p_ccb, p_scb);
|
2016-11-16 03:05:55 +00:00
|
|
|
AVDT_TRACE_DEBUG("avdt_ad_close_req state: %d\n", p_tbl->state);
|
2016-11-02 09:42:26 +00:00
|
|
|
|
2017-03-17 14:46:49 +00:00
|
|
|
switch (p_tbl->state) {
|
2016-11-02 09:42:26 +00:00
|
|
|
case AVDT_AD_ST_UNUSED:
|
|
|
|
/* probably for reporting */
|
|
|
|
break;
|
|
|
|
case AVDT_AD_ST_ACP:
|
|
|
|
/* if we're listening on this channel, send ourselves a close ind */
|
|
|
|
avdt_ad_tc_close_ind(p_tbl, 0);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
/* get tcid from type, scb */
|
|
|
|
tcid = avdt_ad_type_to_tcid(type, p_scb);
|
|
|
|
|
|
|
|
/* call l2cap disconnect req */
|
|
|
|
L2CA_DisconnectReq(avdt_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][tcid].lcid);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-17 07:08:47 +00:00
|
|
|
#endif /* #if (defined(AVDT_INCLUDED) && AVDT_INCLUDED == TRUE) */
|