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