/******************************************************************************
*
* Copyright (C) 1999-2012 Broadcom Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
/*****************************************************************************
*
* This file contains functions callable by an application
* running on top of RFCOMM
*
*****************************************************************************/
#include <string.h>
#include "bt_target.h"
#include "bt_common.h"
#include "rfcdefs.h"
#include "port_api.h"
#include "l2c_api.h"
#include "port_int.h"
#include "rfc_int.h"
#include "bt_utils.h"
#if RFC_DYNAMIC_MEMORY == FALSE
tRFC_CB rfc_cb;
#endif
/*******************************************************************************
**
** Function RFCOMM_StartReq
**
** Description This function handles Start Request from the upper layer.
** If RFCOMM multiplexer channel can not be allocated
** send start not accepted confirmation. Otherwise dispatch
** start event to the state machine.
**
*******************************************************************************/
void RFCOMM_StartReq (tRFC_MCB *p_mcb)
{
rfc_mx_sm_execute (p_mcb, RFC_MX_EVENT_START_REQ, NULL);
}
/*******************************************************************************
**
** Function RFCOMM_StartRsp
**
** Description This function handles Start Response from the upper layer.
** Save upper layer handle and result of the Start Indication
** in the control block and dispatch event to the FSM.
**
*******************************************************************************/
void RFCOMM_StartRsp (tRFC_MCB *p_mcb, UINT16 result)
{
rfc_mx_sm_execute (p_mcb, RFC_MX_EVENT_START_RSP, &result);
}
/*******************************************************************************
**
** Function RFCOMM_DlcEstablishReq
**
** Description This function is called by the user app to establish
** connection with the specific dlci on a specific bd device.
** It will allocate RFCOMM connection control block if not
** allocated before and dispatch open event to the state
** machine.
**
*******************************************************************************/
void RFCOMM_DlcEstablishReq (tRFC_MCB *p_mcb, UINT8 dlci, UINT16 mtu)
{
UNUSED(mtu);
if (p_mcb->state != RFC_MX_STATE_CONNECTED)
{
PORT_DlcEstablishCnf (p_mcb, dlci, 0, RFCOMM_ERROR);
return;
}
tPORT *p_port = port_find_mcb_dlci_port(p_mcb, dlci);
if (p_port == NULL) {
RFCOMM_TRACE_WARNING("%s Unable to find DLCI port dlci:%d", __func__,
dlci);
return;
}
rfc_port_sm_execute(p_port, RFC_EVENT_OPEN, NULL);
}
/*******************************************************************************
**
** Function RFCOMM_DlcEstablishRsp
**
** Description This function is called by the port emulation entity
** acks Establish Indication.
**
*******************************************************************************/
void RFCOMM_DlcEstablishRsp (tRFC_MCB *p_mcb, UINT8 dlci, UINT16 mtu, UINT16 result)
{
UNUSED(mtu);
if ((p_mcb->state != RFC_MX_STATE_CONNECTED) && (result == RFCOMM_SUCCESS))
{
PORT_DlcReleaseInd (p_mcb, dlci);
return;
}
tPORT *p_port = port_find_mcb_dlci_port (p_mcb, dlci);
if (p_port == NULL) {
RFCOMM_TRACE_WARNING("%s Unable to find DLCI port dlci:%d", __func__,
dlci);
return;
}
rfc_port_sm_execute(p_port, RFC_EVENT_ESTABLISH_RSP, &result);
}
/*******************************************************************************
**
** Function RFCOMM_ParNegReq
**
** Description This function is called by the user app to start
** DLC parameter negotiation. Port emulation can send this
** request before actually establishing the DLC. In this
** case the function will allocate RFCOMM connection control
** block.
**
*******************************************************************************/
void RFCOMM_ParNegReq (tRFC_MCB *p_mcb, UINT8 dlci, UINT16 mtu)
{
UINT8 flow;
UINT8 cl;
UINT8 k;
tPORT *p_port = port_find_mcb_dlci_port(p_mcb, dlci);
if (p_port == NULL) {
RFCOMM_TRACE_WARNING("%s Unable to find DLCI port dlci:%d", __func__,
dlci);
return;
}
if (p_mcb->state != RFC_MX_STATE_CONNECTED)
{
p_port->error = PORT_PAR_NEG_FAILED;
return;
}
/* Negotiate the flow control mechanism. If flow control mechanism for */
/* mux has not been set yet, use our default value. If it has been set, */
/* use that value. */
flow = (p_mcb->flow == PORT_FC_UNDEFINED) ? PORT_FC_DEFAULT : p_mcb->flow;
/* Set convergence layer and number of credits (k) */
if (flow == PORT_FC_CREDIT)
{
cl = RFCOMM_PN_CONV_LAYER_CBFC_I;
k = (p_port->credit_rx_max < RFCOMM_K_MAX) ? p_port->credit_rx_max : RFCOMM_K_MAX;
p_port->credit_rx = k;
}
else
{
cl = RFCOMM_PN_CONV_LAYER_TYPE_1;
k = 0;
}
/* Send Parameter Negotiation Command UIH frame */
p_port->rfc.expected_rsp |= RFC_RSP_PN;
rfc_send_pn (p_mcb, dlci, TRUE, mtu, cl, k);
rfc_port_timer_start (p_port, RFC_T2_TIMEOUT) ;
}
/*******************************************************************************
**
** Function RFCOMM_ParNegRsp
**
** Description This function is called by the user app to acknowledge
** DLC parameter negotiation.
**
*******************************************************************************/
void RFCOMM_ParNegRsp (tRFC_MCB *p_mcb, UINT8 dlci, UINT16 mtu, UINT8 cl, UINT8 k)
{
if (p_mcb->state != RFC_MX_STATE_CONNECTED)
return;
/* Send Parameter Negotiation Response UIH frame */
rfc_send_pn (p_mcb, dlci, FALSE, mtu, cl, k);
}
/*******************************************************************************
**
** Function RFCOMM_PortNegReq
**
** Description This function is called by the user app to start
** Remote Port parameter negotiation. Port emulation can
** send this request before actually establishing the DLC.
** In this case the function will allocate RFCOMM connection
** control block.
**
*******************************************************************************/
void RFCOMM_PortNegReq (tRFC_MCB *p_mcb, UINT8 dlci, tPORT_STATE *p_pars)
{
if (p_mcb->state != RFC_MX_STATE_CONNECTED)
{
PORT_PortNegCnf (p_mcb, dlci, NULL, RFCOMM_ERROR);
return;
}
tPORT *p_port = port_find_mcb_dlci_port(p_mcb, dlci);
if (p_port == NULL) {
RFCOMM_TRACE_WARNING("%s Unable to find DLCI port dlci:%d", __func__,
dlci);
return;
}
/* Send Parameter Negotiation Command UIH frame */
if (!p_pars)
p_port->rfc.expected_rsp |= RFC_RSP_RPN_REPLY;
else
p_port->rfc.expected_rsp |= RFC_RSP_RPN;
rfc_send_rpn (p_mcb, dlci, TRUE, p_pars, RFCOMM_RPN_PM_MASK);
rfc_port_timer_start (p_port, RFC_T2_TIMEOUT) ;
}
/*******************************************************************************
**
** Function RFCOMM_PortNegRsp
**
** Description This function is called by the user app to acknowledge
** Port parameters negotiation.
**
*******************************************************************************/
void RFCOMM_PortNegRsp (tRFC_MCB *p_mcb, UINT8 dlci, tPORT_STATE *p_pars,
UINT16 param_mask)
{
if (p_mcb->state != RFC_MX_STATE_CONNECTED)
return;
rfc_send_rpn (p_mcb, dlci, FALSE, p_pars, param_mask);
}
/*******************************************************************************
**
** Function RFCOMM_ControlReq
**
** Description This function is called by the port entity to send control
** parameters to remote port emulation entity.
**
*******************************************************************************/
void RFCOMM_ControlReq (tRFC_MCB *p_mcb, UINT8 dlci, tPORT_CTRL *p_pars)
{
tPORT *p_port = port_find_mcb_dlci_port(p_mcb, dlci);
if (p_port == NULL) {
RFCOMM_TRACE_WARNING("%s Unable to find DLCI port dlci:%d", __func__,
dlci);
return;
}
if ((p_port->state != PORT_STATE_OPENED)
|| (p_port->rfc.state != RFC_STATE_OPENED))
return;
p_port->port_ctrl |= PORT_CTRL_REQ_SENT;
p_port->rfc.expected_rsp |= RFC_RSP_MSC;
rfc_send_msc (p_mcb, dlci, TRUE, p_pars);
rfc_port_timer_start (p_port, RFC_T2_TIMEOUT) ;
}
/*******************************************************************************
**
** Function RFCOMM_FlowReq
**
** Description This function is called by the port entity when flow
** control state has changed. Enable flag passed shows if
** port can accept more data.
**
*******************************************************************************/
void RFCOMM_FlowReq (tRFC_MCB *p_mcb, UINT8 dlci, UINT8 enable)
{
tPORT *p_port = port_find_mcb_dlci_port(p_mcb, dlci);
if (p_port == NULL) {
RFCOMM_TRACE_WARNING("%s Unable to find DLCI port dlci:%d", __func__,
dlci);
return;
}
if ((p_port->state != PORT_STATE_OPENED)
|| (p_port->rfc.state != RFC_STATE_OPENED))
return;
p_port->local_ctrl.fc = !enable;
p_port->rfc.expected_rsp |= RFC_RSP_MSC;
rfc_send_msc (p_mcb, dlci, TRUE, &p_port->local_ctrl);
rfc_port_timer_start (p_port, RFC_T2_TIMEOUT) ;
}
/*******************************************************************************
**
** Function RFCOMM_LineStatusReq
**
** Description This function is called by the port entity when line
** status should be delivered to the peer.
**
*******************************************************************************/
void RFCOMM_LineStatusReq (tRFC_MCB *p_mcb, UINT8 dlci, UINT8 status)
{
tPORT *p_port = port_find_mcb_dlci_port(p_mcb, dlci);
if (p_port == NULL) {
RFCOMM_TRACE_WARNING("%s Unable to find DLCI port dlci:%d", __func__,
dlci);
return;
}
if ((p_port->state != PORT_STATE_OPENED)
|| (p_port->rfc.state != RFC_STATE_OPENED))
return;
p_port->rfc.expected_rsp |= RFC_RSP_RLS;
rfc_send_rls (p_mcb, dlci, TRUE, status);
rfc_port_timer_start (p_port, RFC_T2_TIMEOUT);
}
/*******************************************************************************
**
** Function RFCOMM_DlcReleaseReq
**
** Description This function is called by the PORT unit to close DLC
**
*******************************************************************************/
void RFCOMM_DlcReleaseReq (tRFC_MCB *p_mcb, UINT8 dlci)
{
rfc_port_sm_execute(port_find_mcb_dlci_port (p_mcb, dlci), RFC_EVENT_CLOSE, 0);
}
/*******************************************************************************
**
** Function RFCOMM_DataReq
**
** Description This function is called by the user app to send data buffer
**
*******************************************************************************/
void RFCOMM_DataReq (tRFC_MCB *p_mcb, UINT8 dlci, BT_HDR *p_buf)
{
rfc_port_sm_execute(port_find_mcb_dlci_port (p_mcb, dlci), RFC_EVENT_DATA, p_buf);
}