Home | History | Annotate | Download | only in rfcomm
      1 /******************************************************************************
      2  *
      3  *  Copyright 1999-2012 Broadcom Corporation
      4  *
      5  *  Licensed under the Apache License, Version 2.0 (the "License");
      6  *  you may not use this file except in compliance with the License.
      7  *  You may obtain a copy of the License at:
      8  *
      9  *  http://www.apache.org/licenses/LICENSE-2.0
     10  *
     11  *  Unless required by applicable law or agreed to in writing, software
     12  *  distributed under the License is distributed on an "AS IS" BASIS,
     13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  *  See the License for the specific language governing permissions and
     15  *  limitations under the License.
     16  *
     17  ******************************************************************************/
     18 
     19 /*****************************************************************************
     20  *
     21  * This file contains functions callable by an application
     22  * running on top of RFCOMM
     23  *
     24  *****************************************************************************/
     25 
     26 #include <cstring>
     27 #include "bt_common.h"
     28 #include "bt_target.h"
     29 #include "bt_utils.h"
     30 #include "l2c_api.h"
     31 #include "osi/include/osi.h"
     32 #include "port_api.h"
     33 #include "port_int.h"
     34 #include "rfc_int.h"
     35 #include "rfcdefs.h"
     36 
     37 tRFC_CB rfc_cb;
     38 
     39 /*******************************************************************************
     40  *
     41  * Function         RFCOMM_StartReq
     42  *
     43  * Description      This function handles Start Request from the upper layer.
     44  *                  If RFCOMM multiplexer channel can not be allocated
     45  *                  send start not accepted confirmation.  Otherwise dispatch
     46  *                  start event to the state machine.
     47  *
     48  ******************************************************************************/
     49 void RFCOMM_StartReq(tRFC_MCB* p_mcb) {
     50   rfc_mx_sm_execute(p_mcb, RFC_MX_EVENT_START_REQ, nullptr);
     51 }
     52 
     53 /*******************************************************************************
     54  *
     55  * Function         RFCOMM_StartRsp
     56  *
     57  * Description      This function handles Start Response from the upper layer.
     58  *                  Save upper layer handle and result of the Start Indication
     59  *                  in the control block and dispatch event to the FSM.
     60  *
     61  ******************************************************************************/
     62 void RFCOMM_StartRsp(tRFC_MCB* p_mcb, uint16_t result) {
     63   rfc_mx_sm_execute(p_mcb, RFC_MX_EVENT_START_RSP, &result);
     64 }
     65 
     66 /*******************************************************************************
     67  *
     68  * Function         RFCOMM_DlcEstablishReq
     69  *
     70  * Description      This function is called by the user app to establish
     71  *                  connection with the specific dlci on a specific bd device.
     72  *                  It will allocate RFCOMM connection control block if not
     73  *                  allocated before and dispatch open event to the state
     74  *                  machine.
     75  *
     76  ******************************************************************************/
     77 void RFCOMM_DlcEstablishReq(tRFC_MCB* p_mcb, uint8_t dlci,
     78                             UNUSED_ATTR uint16_t mtu) {
     79   if (p_mcb->state != RFC_MX_STATE_CONNECTED) {
     80     PORT_DlcEstablishCnf(p_mcb, dlci, 0, RFCOMM_ERROR);
     81     return;
     82   }
     83 
     84   tPORT* p_port = port_find_mcb_dlci_port(p_mcb, dlci);
     85   if (p_port == nullptr) {
     86     RFCOMM_TRACE_WARNING("%s Unable to find DLCI port dlci:%d", __func__, dlci);
     87     return;
     88   }
     89 
     90   rfc_port_sm_execute(p_port, RFC_EVENT_OPEN, nullptr);
     91 }
     92 
     93 /*******************************************************************************
     94  *
     95  * Function         RFCOMM_DlcEstablishRsp
     96  *
     97  * Description      This function is called by the port emulation entity
     98  *                  acks Establish Indication.
     99  *
    100  ******************************************************************************/
    101 void RFCOMM_DlcEstablishRsp(tRFC_MCB* p_mcb, uint8_t dlci,
    102                             UNUSED_ATTR uint16_t mtu, uint16_t result) {
    103   if ((p_mcb->state != RFC_MX_STATE_CONNECTED) && (result == RFCOMM_SUCCESS)) {
    104     PORT_DlcReleaseInd(p_mcb, dlci);
    105     return;
    106   }
    107 
    108   tPORT* p_port = port_find_mcb_dlci_port(p_mcb, dlci);
    109   if (p_port == nullptr) {
    110     RFCOMM_TRACE_WARNING("%s Unable to find DLCI port dlci:%d", __func__, dlci);
    111     return;
    112   }
    113   rfc_port_sm_execute(p_port, RFC_EVENT_ESTABLISH_RSP, &result);
    114 }
    115 
    116 /*******************************************************************************
    117  *
    118  * Function         RFCOMM_ParNegReq
    119  *
    120  * Description      This function is called by the user app to start
    121  *                  DLC parameter negotiation.  Port emulation can send this
    122  *                  request before actually establishing the DLC.  In this
    123  *                  case the function will allocate RFCOMM connection control
    124  *                  block.
    125  *
    126  ******************************************************************************/
    127 void RFCOMM_ParNegReq(tRFC_MCB* p_mcb, uint8_t dlci, uint16_t mtu) {
    128   uint8_t flow;
    129   uint8_t cl;
    130   uint8_t k;
    131 
    132   tPORT* p_port = port_find_mcb_dlci_port(p_mcb, dlci);
    133   if (p_port == nullptr) {
    134     RFCOMM_TRACE_WARNING("%s Unable to find DLCI port dlci:%d", __func__, dlci);
    135     return;
    136   }
    137 
    138   if (p_mcb->state != RFC_MX_STATE_CONNECTED) {
    139     p_port->error = PORT_PAR_NEG_FAILED;
    140     return;
    141   }
    142 
    143   /* Negotiate the flow control mechanism.  If flow control mechanism for */
    144   /* mux has not been set yet, use our default value.  If it has been set, */
    145   /* use that value. */
    146   flow = (p_mcb->flow == PORT_FC_UNDEFINED) ? PORT_FC_DEFAULT : p_mcb->flow;
    147 
    148   /* Set convergence layer and number of credits (k) */
    149   if (flow == PORT_FC_CREDIT) {
    150     cl = RFCOMM_PN_CONV_LAYER_CBFC_I;
    151     k = (p_port->credit_rx_max < RFCOMM_K_MAX) ? p_port->credit_rx_max
    152                                                : RFCOMM_K_MAX;
    153     p_port->credit_rx = k;
    154   } else {
    155     cl = RFCOMM_PN_CONV_LAYER_TYPE_1;
    156     k = 0;
    157   }
    158 
    159   /* Send Parameter Negotiation Command UIH frame */
    160   p_port->rfc.expected_rsp |= RFC_RSP_PN;
    161 
    162   rfc_send_pn(p_mcb, dlci, true, mtu, cl, k);
    163 
    164   rfc_port_timer_start(p_port, RFC_T2_TIMEOUT);
    165 }
    166 
    167 /*******************************************************************************
    168  *
    169  * Function         RFCOMM_ParNegRsp
    170  *
    171  * Description      This function is called by the user app to acknowledge
    172  *                  DLC parameter negotiation.
    173  *
    174  ******************************************************************************/
    175 void RFCOMM_ParNegRsp(tRFC_MCB* p_mcb, uint8_t dlci, uint16_t mtu, uint8_t cl,
    176                       uint8_t k) {
    177   if (p_mcb->state != RFC_MX_STATE_CONNECTED) return;
    178 
    179   /* Send Parameter Negotiation Response UIH frame */
    180   rfc_send_pn(p_mcb, dlci, false, mtu, cl, k);
    181 }
    182 
    183 /*******************************************************************************
    184  *
    185  * Function         RFCOMM_PortNegReq
    186  *
    187  * Description      This function is called by the user app to start
    188  *                  Remote Port parameter negotiation.  Port emulation can
    189  *                  send this request before actually establishing the DLC.
    190  *                  In this case the function will allocate RFCOMM connection
    191  *                  control block.
    192  *
    193  ******************************************************************************/
    194 void RFCOMM_PortNegReq(tRFC_MCB* p_mcb, uint8_t dlci, tPORT_STATE* p_pars) {
    195   if (p_mcb->state != RFC_MX_STATE_CONNECTED) {
    196     PORT_PortNegCnf(p_mcb, dlci, nullptr, RFCOMM_ERROR);
    197     return;
    198   }
    199 
    200   tPORT* p_port = port_find_mcb_dlci_port(p_mcb, dlci);
    201   if (p_port == nullptr) {
    202     RFCOMM_TRACE_WARNING("%s Unable to find DLCI port dlci:%d", __func__, dlci);
    203     return;
    204   }
    205 
    206   /* Send Parameter Negotiation Command UIH frame */
    207   if (!p_pars)
    208     p_port->rfc.expected_rsp |= RFC_RSP_RPN_REPLY;
    209   else
    210     p_port->rfc.expected_rsp |= RFC_RSP_RPN;
    211 
    212   rfc_send_rpn(p_mcb, dlci, true, p_pars, RFCOMM_RPN_PM_MASK);
    213   rfc_port_timer_start(p_port, RFC_T2_TIMEOUT);
    214 }
    215 
    216 /*******************************************************************************
    217  *
    218  * Function         RFCOMM_PortNegRsp
    219  *
    220  * Description      This function is called by the user app to acknowledge
    221  *                  Port parameters negotiation.
    222  *
    223  ******************************************************************************/
    224 void RFCOMM_PortNegRsp(tRFC_MCB* p_mcb, uint8_t dlci, tPORT_STATE* p_pars,
    225                        uint16_t param_mask) {
    226   if (p_mcb->state != RFC_MX_STATE_CONNECTED) return;
    227 
    228   rfc_send_rpn(p_mcb, dlci, false, p_pars, param_mask);
    229 }
    230 
    231 /*******************************************************************************
    232  *
    233  * Function         RFCOMM_ControlReq
    234  *
    235  * Description      This function is called by the port entity to send control
    236  *                  parameters to remote port emulation entity.
    237  *
    238  ******************************************************************************/
    239 void RFCOMM_ControlReq(tRFC_MCB* p_mcb, uint8_t dlci, tPORT_CTRL* p_pars) {
    240   tPORT* p_port = port_find_mcb_dlci_port(p_mcb, dlci);
    241   if (p_port == nullptr) {
    242     RFCOMM_TRACE_WARNING("%s Unable to find DLCI port dlci:%d", __func__, dlci);
    243     return;
    244   }
    245 
    246   if ((p_port->state != PORT_STATE_OPENED) ||
    247       (p_port->rfc.state != RFC_STATE_OPENED))
    248     return;
    249 
    250   p_port->port_ctrl |= PORT_CTRL_REQ_SENT;
    251 
    252   p_port->rfc.expected_rsp |= RFC_RSP_MSC;
    253 
    254   rfc_send_msc(p_mcb, dlci, true, p_pars);
    255   rfc_port_timer_start(p_port, RFC_T2_TIMEOUT);
    256 }
    257 
    258 /*******************************************************************************
    259  *
    260  * Function         RFCOMM_FlowReq
    261  *
    262  * Description      This function is called by the port entity when flow
    263  *                  control state has changed.  Enable flag passed shows if
    264  *                  port can accept more data.
    265  *
    266  ******************************************************************************/
    267 void RFCOMM_FlowReq(tRFC_MCB* p_mcb, uint8_t dlci, bool enable) {
    268   tPORT* p_port = port_find_mcb_dlci_port(p_mcb, dlci);
    269   if (p_port == nullptr) {
    270     RFCOMM_TRACE_WARNING("%s Unable to find DLCI port dlci:%d", __func__, dlci);
    271     return;
    272   }
    273 
    274   if ((p_port->state != PORT_STATE_OPENED) ||
    275       (p_port->rfc.state != RFC_STATE_OPENED))
    276     return;
    277 
    278   p_port->local_ctrl.fc = !enable;
    279 
    280   p_port->rfc.expected_rsp |= RFC_RSP_MSC;
    281 
    282   rfc_send_msc(p_mcb, dlci, true, &p_port->local_ctrl);
    283   rfc_port_timer_start(p_port, RFC_T2_TIMEOUT);
    284 }
    285 
    286 /*******************************************************************************
    287  *
    288  * Function         RFCOMM_LineStatusReq
    289  *
    290  * Description      This function is called by the port entity when line
    291  *                  status should be delivered to the peer.
    292  *
    293  ******************************************************************************/
    294 void RFCOMM_LineStatusReq(tRFC_MCB* p_mcb, uint8_t dlci, uint8_t status) {
    295   tPORT* p_port = port_find_mcb_dlci_port(p_mcb, dlci);
    296   if (p_port == nullptr) {
    297     RFCOMM_TRACE_WARNING("%s Unable to find DLCI port dlci:%d", __func__, dlci);
    298     return;
    299   }
    300 
    301   if ((p_port->state != PORT_STATE_OPENED) ||
    302       (p_port->rfc.state != RFC_STATE_OPENED))
    303     return;
    304 
    305   p_port->rfc.expected_rsp |= RFC_RSP_RLS;
    306 
    307   rfc_send_rls(p_mcb, dlci, true, status);
    308   rfc_port_timer_start(p_port, RFC_T2_TIMEOUT);
    309 }
    310 
    311 /*******************************************************************************
    312  *
    313  * Function         RFCOMM_DlcReleaseReq
    314  *
    315  * Description      This function is called by the PORT unit to close DLC
    316  *
    317  ******************************************************************************/
    318 void RFCOMM_DlcReleaseReq(tRFC_MCB* p_mcb, uint8_t dlci) {
    319   rfc_port_sm_execute(port_find_mcb_dlci_port(p_mcb, dlci), RFC_EVENT_CLOSE,
    320                       nullptr);
    321 }
    322 
    323 /*******************************************************************************
    324  *
    325  * Function         RFCOMM_DataReq
    326  *
    327  * Description      This function is called by the user app to send data buffer
    328  *
    329  ******************************************************************************/
    330 void RFCOMM_DataReq(tRFC_MCB* p_mcb, uint8_t dlci, BT_HDR* p_buf) {
    331   rfc_port_sm_execute(port_find_mcb_dlci_port(p_mcb, dlci), RFC_EVENT_DATA,
    332                       p_buf);
    333 }
    334