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