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 L2CAP interface functions
     22  *
     23  ******************************************************************************/
     24 
     25 #include <stddef.h>
     26 #include "bt_target.h"
     27 
     28 #include "bt_common.h"
     29 #include "osi/include/osi.h"
     30 #include "osi/include/time.h"
     31 
     32 #include "bt_utils.h"
     33 #include "l2c_api.h"
     34 #include "l2cdefs.h"
     35 #include "port_api.h"
     36 #include "port_int.h"
     37 #include "rfc_int.h"
     38 #include "rfcdefs.h"
     39 
     40 /*
     41  * Define Callback functions to be called by L2CAP
     42 */
     43 static void RFCOMM_ConnectInd(const RawAddress& bd_addr, uint16_t lcid,
     44                               uint16_t psm, uint8_t id);
     45 static void RFCOMM_ConnectCnf(uint16_t lcid, uint16_t err);
     46 static void RFCOMM_ConfigInd(uint16_t lcid, tL2CAP_CFG_INFO* p_cfg);
     47 static void RFCOMM_ConfigCnf(uint16_t lcid, tL2CAP_CFG_INFO* p_cfg);
     48 static void RFCOMM_DisconnectInd(uint16_t lcid, bool is_clear);
     49 static void RFCOMM_QoSViolationInd(UNUSED_ATTR const RawAddress& bd_addr);
     50 static void RFCOMM_BufDataInd(uint16_t lcid, BT_HDR* p_buf);
     51 static void RFCOMM_CongestionStatusInd(uint16_t lcid, bool is_congested);
     52 
     53 /*******************************************************************************
     54  *
     55  * Function         rfcomm_l2cap_if_init
     56  *
     57  * Description      This function is called during the RFCOMM task startup
     58  *                  to register interface functions with L2CAP.
     59  *
     60  ******************************************************************************/
     61 void rfcomm_l2cap_if_init(void) {
     62   tL2CAP_APPL_INFO* p_l2c = &rfc_cb.rfc.reg_info;
     63 
     64   p_l2c->pL2CA_ConnectInd_Cb = RFCOMM_ConnectInd;
     65   p_l2c->pL2CA_ConnectCfm_Cb = RFCOMM_ConnectCnf;
     66   p_l2c->pL2CA_ConnectPnd_Cb = NULL;
     67   p_l2c->pL2CA_ConfigInd_Cb = RFCOMM_ConfigInd;
     68   p_l2c->pL2CA_ConfigCfm_Cb = RFCOMM_ConfigCnf;
     69   p_l2c->pL2CA_DisconnectInd_Cb = RFCOMM_DisconnectInd;
     70   p_l2c->pL2CA_DisconnectCfm_Cb = NULL;
     71   p_l2c->pL2CA_QoSViolationInd_Cb = RFCOMM_QoSViolationInd;
     72   p_l2c->pL2CA_DataInd_Cb = RFCOMM_BufDataInd;
     73   p_l2c->pL2CA_CongestionStatus_Cb = RFCOMM_CongestionStatusInd;
     74   p_l2c->pL2CA_TxComplete_Cb = NULL;
     75 
     76   L2CA_Register(BT_PSM_RFCOMM, p_l2c);
     77 }
     78 
     79 /*******************************************************************************
     80  *
     81  * Function         RFCOMM_ConnectInd
     82  *
     83  * Description      This is a callback function called by L2CAP when
     84  *                  L2CA_ConnectInd received.  Allocate multiplexer control
     85  *                  block and dispatch the event to it.
     86  *
     87  ******************************************************************************/
     88 void RFCOMM_ConnectInd(const RawAddress& bd_addr, uint16_t lcid,
     89                        UNUSED_ATTR uint16_t psm, uint8_t id) {
     90   tRFC_MCB* p_mcb = rfc_alloc_multiplexer_channel(bd_addr, false);
     91 
     92   if ((p_mcb) && (p_mcb->state != RFC_MX_STATE_IDLE)) {
     93     /* if this is collision case */
     94     if ((p_mcb->is_initiator) && (p_mcb->state == RFC_MX_STATE_WAIT_CONN_CNF)) {
     95       p_mcb->pending_lcid = lcid;
     96       p_mcb->pending_id = id;
     97 
     98       /* wait random timeout (2 - 12) to resolve collision */
     99       /* if peer gives up then local device rejects incoming connection and
    100        * continues as initiator */
    101       /* if timeout, local device disconnects outgoing connection and continues
    102        * as acceptor */
    103       RFCOMM_TRACE_DEBUG(
    104           "RFCOMM_ConnectInd start timer for collision, initiator's "
    105           "LCID(0x%x), acceptor's LCID(0x%x)",
    106           p_mcb->lcid, p_mcb->pending_lcid);
    107 
    108       rfc_timer_start(p_mcb, (uint16_t)(time_get_os_boottime_ms() % 10 + 2));
    109       return;
    110     } else {
    111       /* we cannot accept connection request from peer at this state */
    112       /* don't update lcid */
    113       p_mcb = NULL;
    114     }
    115   } else {
    116     /* store mcb even if null */
    117     rfc_save_lcid_mcb(p_mcb, lcid);
    118   }
    119 
    120   if (p_mcb == NULL) {
    121     L2CA_ConnectRsp(bd_addr, id, lcid, L2CAP_CONN_NO_RESOURCES, 0);
    122     return;
    123   }
    124   p_mcb->lcid = lcid;
    125 
    126   rfc_mx_sm_execute(p_mcb, RFC_MX_EVENT_CONN_IND, &id);
    127 }
    128 
    129 /*******************************************************************************
    130  *
    131  * Function         RFCOMM_ConnectCnf
    132  *
    133  * Description      This is a callback function called by L2CAP when
    134  *                  L2CA_ConnectCnf received.  Save L2CAP handle and dispatch
    135  *                  event to the FSM.
    136  *
    137  ******************************************************************************/
    138 void RFCOMM_ConnectCnf(uint16_t lcid, uint16_t result) {
    139   tRFC_MCB* p_mcb = rfc_find_lcid_mcb(lcid);
    140 
    141   if (!p_mcb) {
    142     RFCOMM_TRACE_ERROR("RFCOMM_ConnectCnf LCID:0x%x", lcid);
    143     return;
    144   }
    145 
    146   if (p_mcb->pending_lcid) {
    147     /* if peer rejects our connect request but peer's connect request is pending
    148      */
    149     if (result != L2CAP_CONN_OK) {
    150       RFCOMM_TRACE_DEBUG(
    151           "RFCOMM_ConnectCnf retry as acceptor on pending LCID(0x%x)",
    152           p_mcb->pending_lcid);
    153 
    154       /* remove mcb from mapping table */
    155       rfc_save_lcid_mcb(NULL, p_mcb->lcid);
    156 
    157       p_mcb->lcid = p_mcb->pending_lcid;
    158       p_mcb->is_initiator = false;
    159       p_mcb->state = RFC_MX_STATE_IDLE;
    160 
    161       /* store mcb into mapping table */
    162       rfc_save_lcid_mcb(p_mcb, p_mcb->lcid);
    163 
    164       /* update direction bit */
    165       for (int i = 0; i < RFCOMM_MAX_DLCI; i += 2) {
    166         uint8_t idx = p_mcb->port_inx[i];
    167         if (idx != 0) {
    168           p_mcb->port_inx[i] = 0;
    169           p_mcb->port_inx[i + 1] = idx;
    170           rfc_cb.port.port[idx - 1].dlci += 1;
    171           RFCOMM_TRACE_DEBUG("RFCOMM MX, port_handle=%d, DLCI[%d->%d]", idx, i,
    172                              rfc_cb.port.port[idx - 1].dlci);
    173         }
    174       }
    175 
    176       rfc_mx_sm_execute(p_mcb, RFC_MX_EVENT_CONN_IND, &(p_mcb->pending_id));
    177       return;
    178     } else {
    179       RFCOMM_TRACE_DEBUG("RFCOMM_ConnectCnf peer gave up pending LCID(0x%x)",
    180                          p_mcb->pending_lcid);
    181 
    182       /* Peer gave up his connection request, make sure cleaning up L2CAP
    183        * channel */
    184       L2CA_ConnectRsp(p_mcb->bd_addr, p_mcb->pending_id, p_mcb->pending_lcid,
    185                       L2CAP_CONN_NO_RESOURCES, 0);
    186 
    187       p_mcb->pending_lcid = 0;
    188     }
    189   }
    190 
    191   /* Save LCID to be used in all consecutive calls to L2CAP */
    192   p_mcb->lcid = lcid;
    193 
    194   rfc_mx_sm_execute(p_mcb, RFC_MX_EVENT_CONN_CNF, &result);
    195 }
    196 
    197 /*******************************************************************************
    198  *
    199  * Function         RFCOMM_ConfigInd
    200  *
    201  * Description      This is a callback function called by L2CAP when
    202  *                  L2CA_ConfigInd received.  Save parameters in the control
    203  *                  block and dispatch event to the FSM.
    204  *
    205  ******************************************************************************/
    206 void RFCOMM_ConfigInd(uint16_t lcid, tL2CAP_CFG_INFO* p_cfg) {
    207   tRFC_MCB* p_mcb = rfc_find_lcid_mcb(lcid);
    208 
    209   if (!p_mcb) {
    210     RFCOMM_TRACE_ERROR("RFCOMM_ConfigInd LCID:0x%x", lcid);
    211     return;
    212   }
    213 
    214   rfc_mx_sm_execute(p_mcb, RFC_MX_EVENT_CONF_IND, (void*)p_cfg);
    215 }
    216 
    217 /*******************************************************************************
    218  *
    219  * Function         RFCOMM_ConfigCnf
    220  *
    221  * Description      This is a callback function called by L2CAP when
    222  *                  L2CA_ConfigCnf received.  Save L2CAP handle and dispatch
    223  *                  event to the FSM.
    224  *
    225  ******************************************************************************/
    226 void RFCOMM_ConfigCnf(uint16_t lcid, tL2CAP_CFG_INFO* p_cfg) {
    227   tRFC_MCB* p_mcb = rfc_find_lcid_mcb(lcid);
    228 
    229   if (!p_mcb) {
    230     RFCOMM_TRACE_ERROR("RFCOMM_ConfigCnf no MCB LCID:0x%x", lcid);
    231     return;
    232   }
    233 
    234   rfc_mx_sm_execute(p_mcb, RFC_MX_EVENT_CONF_CNF, (void*)p_cfg);
    235 }
    236 
    237 /*******************************************************************************
    238  *
    239  * Function         RFCOMM_QoSViolationInd
    240  *
    241  * Description      This is a callback function called by L2CAP when
    242  *                  L2CA_QoSViolationIndInd received.  Dispatch event to the
    243  *                  FSM.
    244  *
    245  ******************************************************************************/
    246 void RFCOMM_QoSViolationInd(UNUSED_ATTR const RawAddress& bd_addr) {}
    247 
    248 /*******************************************************************************
    249  *
    250  * Function         RFCOMM_DisconnectInd
    251  *
    252  * Description      This is a callback function called by L2CAP when
    253  *                  L2CA_DisconnectInd received.  Dispatch event to the FSM.
    254  *
    255  ******************************************************************************/
    256 void RFCOMM_DisconnectInd(uint16_t lcid, bool is_conf_needed) {
    257   tRFC_MCB* p_mcb = rfc_find_lcid_mcb(lcid);
    258 
    259   if (is_conf_needed) {
    260     L2CA_DisconnectRsp(lcid);
    261   }
    262 
    263   if (!p_mcb) {
    264     RFCOMM_TRACE_WARNING("RFCOMM_DisconnectInd LCID:0x%x", lcid);
    265     return;
    266   }
    267 
    268   rfc_mx_sm_execute(p_mcb, RFC_MX_EVENT_DISC_IND, nullptr);
    269 }
    270 
    271 /*******************************************************************************
    272  *
    273  * Function         RFCOMM_BufDataInd
    274  *
    275  * Description      This is a callback function called by L2CAP when
    276  *                  data RFCOMM frame is received.  Parse the frames, check
    277  *                  the checksum and dispatch event to multiplexer or port
    278  *                  state machine depending on the frame destination.
    279  *
    280  ******************************************************************************/
    281 void RFCOMM_BufDataInd(uint16_t lcid, BT_HDR* p_buf) {
    282   tRFC_MCB* p_mcb = rfc_find_lcid_mcb(lcid);
    283 
    284   if (!p_mcb) {
    285     LOG(WARNING) << __func__ << ": Cannot find RFCOMM multiplexer for lcid "
    286                  << loghex(lcid);
    287     osi_free(p_buf);
    288     return;
    289   }
    290 
    291   uint8_t event = rfc_parse_data(p_mcb, &rfc_cb.rfc.rx_frame, p_buf);
    292 
    293   /* If the frame did not pass validation just ignore it */
    294   if (event == RFC_EVENT_BAD_FRAME) {
    295     LOG(WARNING) << __func__ << ": Bad RFCOMM frame from lcid=" << loghex(lcid)
    296                  << ", bd_addr=" << p_mcb->bd_addr << ", p_mcb=" << p_mcb;
    297     osi_free(p_buf);
    298     return;
    299   }
    300 
    301   if (rfc_cb.rfc.rx_frame.dlci == RFCOMM_MX_DLCI) {
    302     RFCOMM_TRACE_DEBUG("%s: Handle multiplexer event %d, p_mcb=%p", __func__,
    303                        event, p_mcb);
    304     /* Take special care of the Multiplexer Control Messages */
    305     if (event == RFC_EVENT_UIH) {
    306       rfc_process_mx_message(p_mcb, p_buf);
    307       return;
    308     }
    309 
    310     /* Other multiplexer events go to state machine */
    311     rfc_mx_sm_execute(p_mcb, event, nullptr);
    312     osi_free(p_buf);
    313     return;
    314   }
    315 
    316   /* The frame was received on the data channel DLCI, verify that DLC exists */
    317   tPORT* p_port = port_find_mcb_dlci_port(p_mcb, rfc_cb.rfc.rx_frame.dlci);
    318   if (p_port == nullptr || !p_port->rfc.p_mcb) {
    319     /* If this is a SABME on new port, check if any app is waiting for it */
    320     if (event != RFC_EVENT_SABME) {
    321       LOG(WARNING) << __func__
    322                    << ": no for none-SABME event, lcid=" << loghex(lcid)
    323                    << ", bd_addr=" << p_mcb->bd_addr << ", p_mcb=" << p_mcb;
    324       if ((p_mcb->is_initiator && !rfc_cb.rfc.rx_frame.cr) ||
    325           (!p_mcb->is_initiator && rfc_cb.rfc.rx_frame.cr)) {
    326         LOG(ERROR) << __func__
    327                    << ": Disconnecting RFCOMM, lcid=" << loghex(lcid)
    328                    << ", bd_addr=" << p_mcb->bd_addr << ", p_mcb=" << p_mcb;
    329         rfc_send_dm(p_mcb, rfc_cb.rfc.rx_frame.dlci, rfc_cb.rfc.rx_frame.pf);
    330       }
    331       osi_free(p_buf);
    332       return;
    333     }
    334 
    335     p_port = port_find_dlci_port(rfc_cb.rfc.rx_frame.dlci);
    336     if (p_port == nullptr) {
    337       LOG(ERROR) << __func__ << ":Disconnecting RFCOMM, no port for dlci "
    338                  << +rfc_cb.rfc.rx_frame.dlci << ", lcid=" << loghex(lcid)
    339                  << ", bd_addr=" << p_mcb->bd_addr << ", p_mcb=" << p_mcb;
    340       rfc_send_dm(p_mcb, rfc_cb.rfc.rx_frame.dlci, true);
    341       osi_free(p_buf);
    342       return;
    343     }
    344     RFCOMM_TRACE_DEBUG("%s: port_inx[dlci=%d]:%d->%d, p_mcb=%p", __func__,
    345                        rfc_cb.rfc.rx_frame.dlci,
    346                        p_mcb->port_inx[rfc_cb.rfc.rx_frame.dlci], p_port->inx);
    347     p_mcb->port_inx[rfc_cb.rfc.rx_frame.dlci] = p_port->inx;
    348     p_port->rfc.p_mcb = p_mcb;
    349   }
    350 
    351   if (event == RFC_EVENT_UIH) {
    352     RFCOMM_TRACE_DEBUG("%s: Handling UIH event, buf_len=%u, credit=%u",
    353                        __func__, p_buf->len, rfc_cb.rfc.rx_frame.credit);
    354     if (p_buf->len > 0) {
    355       rfc_port_sm_execute(p_port, event, p_buf);
    356     } else {
    357       osi_free(p_buf);
    358     }
    359 
    360     if (rfc_cb.rfc.rx_frame.credit != 0) {
    361       rfc_inc_credit(p_port, rfc_cb.rfc.rx_frame.credit);
    362     }
    363 
    364     return;
    365   }
    366   rfc_port_sm_execute(p_port, event, nullptr);
    367   osi_free(p_buf);
    368 }
    369 
    370 /*******************************************************************************
    371  *
    372  * Function         RFCOMM_CongestionStatusInd
    373  *
    374  * Description      This is a callback function called by L2CAP when
    375  *                  data RFCOMM L2CAP congestion status changes
    376  *
    377  ******************************************************************************/
    378 void RFCOMM_CongestionStatusInd(uint16_t lcid, bool is_congested) {
    379   tRFC_MCB* p_mcb = rfc_find_lcid_mcb(lcid);
    380 
    381   if (!p_mcb) {
    382     RFCOMM_TRACE_ERROR("RFCOMM_CongestionStatusInd dropped LCID:0x%x", lcid);
    383     return;
    384   } else {
    385     RFCOMM_TRACE_EVENT("RFCOMM_CongestionStatusInd LCID:0x%x", lcid);
    386   }
    387   rfc_process_l2cap_congestion(p_mcb, is_congested);
    388 }
    389 
    390 /*******************************************************************************
    391  *
    392  * Function         rfc_find_lcid_mcb
    393  *
    394  * Description      This function returns MCB block supporting local cid
    395  *
    396  ******************************************************************************/
    397 tRFC_MCB* rfc_find_lcid_mcb(uint16_t lcid) {
    398   if (lcid - L2CAP_BASE_APPL_CID >= MAX_L2CAP_CHANNELS) {
    399     RFCOMM_TRACE_ERROR("rfc_find_lcid_mcb LCID:0x%x", lcid);
    400     return nullptr;
    401   } else {
    402     tRFC_MCB* p_mcb = rfc_cb.rfc.p_rfc_lcid_mcb[lcid - L2CAP_BASE_APPL_CID];
    403     if (p_mcb != nullptr) {
    404       if (p_mcb->lcid != lcid) {
    405         LOG(WARNING) << __func__ << "LCID reused lcid=:" << loghex(lcid)
    406                      << ", current_lcid=" << loghex(p_mcb->lcid);
    407         return nullptr;
    408       }
    409     }
    410     return p_mcb;
    411   }
    412 }
    413 
    414 /*******************************************************************************
    415  *
    416  * Function         rfc_save_lcid_mcb
    417  *
    418  * Description      This function returns MCB block supporting local cid
    419  *
    420  ******************************************************************************/
    421 void rfc_save_lcid_mcb(tRFC_MCB* p_mcb, uint16_t lcid) {
    422   if (lcid < L2CAP_BASE_APPL_CID) return;
    423   rfc_cb.rfc.p_rfc_lcid_mcb[lcid - L2CAP_BASE_APPL_CID] = p_mcb;
    424 }
    425