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