| /****************************************************************************** |
| * |
| * Copyright 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 <cstring> |
| #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, nullptr); |
| } |
| |
| /******************************************************************************* |
| * |
| * 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 == nullptr) { |
| RFCOMM_TRACE_WARNING("%s Unable to find DLCI port dlci:%d", __func__, dlci); |
| return; |
| } |
| |
| rfc_port_sm_execute(p_port, RFC_EVENT_OPEN, nullptr); |
| } |
| |
| /******************************************************************************* |
| * |
| * 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 == nullptr) { |
| 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_ParameterNegotiationRequest |
| * |
| * 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_ParameterNegotiationRequest(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 == nullptr) { |
| 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_ParameterNegotiationResponse |
| * |
| * Description This function is called by the user app to acknowledge |
| * DLC parameter negotiation. |
| * |
| ******************************************************************************/ |
| void RFCOMM_ParameterNegotiationResponse(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_PortParameterNegotiationRequest |
| * |
| * 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_PortParameterNegotiationRequest(tRFC_MCB* p_mcb, uint8_t dlci, |
| tPORT_STATE* p_pars) { |
| if (p_mcb->state != RFC_MX_STATE_CONNECTED) { |
| PORT_PortNegCnf(p_mcb, dlci, nullptr, RFCOMM_ERROR); |
| return; |
| } |
| |
| tPORT* p_port = port_find_mcb_dlci_port(p_mcb, dlci); |
| if (p_port == nullptr) { |
| 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_PortParameterNegotiationResponse |
| * |
| * Description This function is called by the user app to acknowledge |
| * Port parameters negotiation. |
| * |
| ******************************************************************************/ |
| void RFCOMM_PortParameterNegotiationResponse(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 == nullptr) { |
| 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, bool enable) { |
| tPORT* p_port = port_find_mcb_dlci_port(p_mcb, dlci); |
| if (p_port == nullptr) { |
| 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 == nullptr) { |
| 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, |
| nullptr); |
| } |
| |
| /******************************************************************************* |
| * |
| * 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); |
| } |