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