You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
332 lines
12 KiB
332 lines
12 KiB
/****************************************************************************** |
|
* |
|
* 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_common.h" |
|
#include "bt_target.h" |
|
#include "bt_utils.h" |
|
#include "l2c_api.h" |
|
#include "osi/include/osi.h" |
|
#include "port_api.h" |
|
#include "port_int.h" |
|
#include "rfc_int.h" |
|
#include "rfcdefs.h" |
|
|
|
tRFC_CB rfc_cb; |
|
|
|
/******************************************************************************* |
|
* |
|
* 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_t 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_t dlci, |
|
UNUSED_ATTR uint16_t 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_t dlci, |
|
UNUSED_ATTR uint16_t mtu, uint16_t result) { |
|
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_t dlci, uint16_t mtu) { |
|
uint8_t flow; |
|
uint8_t cl; |
|
uint8_t 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_t dlci, uint16_t mtu, uint8_t cl, |
|
uint8_t 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_t 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_t dlci, tPORT_STATE* p_pars, |
|
uint16_t 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_t 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_t dlci, uint8_t 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_t dlci, uint8_t 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_t 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_t dlci, BT_HDR* p_buf) { |
|
rfc_port_sm_execute(port_find_mcb_dlci_port(p_mcb, dlci), RFC_EVENT_DATA, |
|
p_buf); |
|
}
|
|
|