Home | History | Annotate | Download | only in mcap
      1 /******************************************************************************
      2  *
      3  *  Copyright 2009-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 is the implementation file for the MCAP Main Control Block and
     22  *  Utility functions.
     23  *
     24  ******************************************************************************/
     25 #include <base/logging.h>
     26 #include <string.h>
     27 
     28 #include "bt_common.h"
     29 #include "bt_target.h"
     30 #include "l2c_api.h"
     31 #include "mca_api.h"
     32 #include "mca_defs.h"
     33 #include "mca_int.h"
     34 
     35 /* Main Control block for MCA */
     36 tMCA_CB mca_cb;
     37 
     38 /*****************************************************************************
     39  * constants
     40  ****************************************************************************/
     41 
     42 /* table of standard opcode message size */
     43 const uint8_t mca_std_msg_len[MCA_NUM_STANDARD_OPCODE] = {
     44     4, /* MCA_OP_ERROR_RSP         */
     45     5, /* MCA_OP_MDL_CREATE_REQ    */
     46     5, /* MCA_OP_MDL_CREATE_RSP    */
     47     3, /* MCA_OP_MDL_RECONNECT_REQ */
     48     4, /* MCA_OP_MDL_RECONNECT_RSP */
     49     3, /* MCA_OP_MDL_ABORT_REQ     */
     50     4, /* MCA_OP_MDL_ABORT_RSP     */
     51     3, /* MCA_OP_MDL_DELETE_REQ    */
     52     4  /* MCA_OP_MDL_DELETE_RSP    */
     53 };
     54 
     55 /*******************************************************************************
     56  *
     57  * Function         mca_handle_by_cpsm
     58  *
     59  * Description      This function returns the handle for the given control
     60  *                  channel PSM. 0, if not found.
     61  *
     62  * Returns          the MCA handle.
     63  *
     64  ******************************************************************************/
     65 tMCA_HANDLE mca_handle_by_cpsm(uint16_t psm) {
     66   int i;
     67   tMCA_HANDLE handle = 0;
     68   tMCA_RCB* p_rcb = &mca_cb.rcb[0];
     69 
     70   for (i = 0; i < MCA_NUM_REGS; i++, p_rcb++) {
     71     if (p_rcb->p_cback && p_rcb->reg.ctrl_psm == psm) {
     72       handle = i + 1;
     73       break;
     74     }
     75   }
     76   return handle;
     77 }
     78 
     79 /*******************************************************************************
     80  *
     81  * Function         mca_handle_by_dpsm
     82  *
     83  * Description      This function returns the handle for the given data
     84  *                  channel PSM. 0, if not found.
     85  *
     86  * Returns          the MCA handle.
     87  *
     88  ******************************************************************************/
     89 tMCA_HANDLE mca_handle_by_dpsm(uint16_t psm) {
     90   int i;
     91   tMCA_HANDLE handle = 0;
     92   tMCA_RCB* p_rcb = &mca_cb.rcb[0];
     93 
     94   for (i = 0; i < MCA_NUM_REGS; i++, p_rcb++) {
     95     if (p_rcb->p_cback && p_rcb->reg.data_psm == psm) {
     96       handle = i + 1;
     97       break;
     98     }
     99   }
    100   return handle;
    101 }
    102 
    103 /*******************************************************************************
    104  *
    105  * Function         mca_tc_tbl_calloc
    106  *
    107  * Description      This function allocates a transport table for the given
    108  *                  control channel.
    109  *
    110  * Returns          The tranport table.
    111  *
    112  ******************************************************************************/
    113 tMCA_TC_TBL* mca_tc_tbl_calloc(tMCA_CCB* p_ccb) {
    114   tMCA_TC_TBL* p_tbl = mca_cb.tc.tc_tbl;
    115   int i;
    116 
    117   /* find next free entry in tc table */
    118   for (i = 0; i < MCA_NUM_TC_TBL; i++, p_tbl++) {
    119     if (p_tbl->state == MCA_TC_ST_UNUSED) {
    120       break;
    121     }
    122   }
    123 
    124   /* sanity check */
    125   CHECK(i != MCA_NUM_TC_TBL);
    126 
    127   /* initialize entry */
    128   p_tbl->peer_mtu = L2CAP_DEFAULT_MTU;
    129   p_tbl->cfg_flags = 0;
    130   p_tbl->cb_idx = mca_ccb_to_hdl(p_ccb);
    131   p_tbl->tcid = MCA_CTRL_TCID;
    132   p_tbl->my_mtu = MCA_CTRL_MTU;
    133   p_tbl->state = MCA_TC_ST_IDLE;
    134   p_tbl->lcid = p_ccb->lcid;
    135   mca_cb.tc.lcid_tbl[p_ccb->lcid - L2CAP_BASE_APPL_CID] = i;
    136 
    137   MCA_TRACE_DEBUG("%s() - cb_idx: %d", __func__, p_tbl->cb_idx);
    138   return p_tbl;
    139 }
    140 
    141 /*******************************************************************************
    142  *
    143  * Function         mca_tc_tbl_dalloc
    144  *
    145  * Description      This function allocates a transport table for the given
    146  *                  data channel.
    147  *
    148  * Returns          The tranport table.
    149  *
    150  ******************************************************************************/
    151 tMCA_TC_TBL* mca_tc_tbl_dalloc(tMCA_DCB* p_dcb) {
    152   tMCA_TC_TBL* p_tbl = mca_cb.tc.tc_tbl;
    153   int i;
    154 
    155   /* find next free entry in tc table */
    156   for (i = 0; i < MCA_NUM_TC_TBL; i++, p_tbl++) {
    157     if (p_tbl->state == MCA_TC_ST_UNUSED) {
    158       break;
    159     }
    160   }
    161 
    162   /* sanity check */
    163   CHECK(i != MCA_NUM_TC_TBL);
    164 
    165   /* initialize entry */
    166   p_tbl->peer_mtu = L2CAP_DEFAULT_MTU;
    167   p_tbl->cfg_flags = 0;
    168   p_tbl->cb_idx = mca_dcb_to_hdl(p_dcb);
    169   p_tbl->tcid = p_dcb->p_cs->type + 1;
    170   p_tbl->my_mtu = p_dcb->p_chnl_cfg->data_mtu;
    171   p_tbl->state = MCA_TC_ST_IDLE;
    172   p_tbl->lcid = p_dcb->lcid;
    173   mca_cb.tc.lcid_tbl[p_dcb->lcid - L2CAP_BASE_APPL_CID] = i;
    174 
    175   MCA_TRACE_DEBUG("%s() - tcid: %d, cb_idx: %d", __func__, p_tbl->tcid,
    176                   p_tbl->cb_idx);
    177   return p_tbl;
    178 }
    179 
    180 /*******************************************************************************
    181  *
    182  * Function         mca_tc_tbl_by_lcid
    183  *
    184  * Description      Find the transport channel table entry by LCID.
    185  *
    186  *
    187  * Returns          The tranport table.
    188  *
    189  ******************************************************************************/
    190 tMCA_TC_TBL* mca_tc_tbl_by_lcid(uint16_t lcid) {
    191   uint8_t idx;
    192 
    193   if (lcid >= L2CAP_BASE_APPL_CID) {
    194     idx = mca_cb.tc.lcid_tbl[lcid - L2CAP_BASE_APPL_CID];
    195 
    196     if (idx < MCA_NUM_TC_TBL) {
    197       return &mca_cb.tc.tc_tbl[idx];
    198     }
    199   }
    200   return NULL;
    201 }
    202 
    203 /*******************************************************************************
    204  *
    205  * Function         mca_free_tc_tbl_by_lcid
    206  *
    207  * Description      Find the  transport table entry by LCID
    208  *                  and free the tc_tbl
    209  *
    210  * Returns          void.
    211  *
    212  ******************************************************************************/
    213 void mca_free_tc_tbl_by_lcid(uint16_t lcid) {
    214   uint8_t idx;
    215 
    216   if (lcid >= L2CAP_BASE_APPL_CID) {
    217     idx = mca_cb.tc.lcid_tbl[lcid - L2CAP_BASE_APPL_CID];
    218 
    219     if (idx < MCA_NUM_TC_TBL) {
    220       mca_cb.tc.tc_tbl[idx].state = MCA_TC_ST_UNUSED;
    221     }
    222   }
    223 }
    224 
    225 /*******************************************************************************
    226  *
    227  * Function         mca_set_cfg_by_tbl
    228  *
    229  * Description      Set the L2CAP configuration information
    230  *
    231  * Returns          none.
    232  *
    233  ******************************************************************************/
    234 void mca_set_cfg_by_tbl(tL2CAP_CFG_INFO* p_cfg, tMCA_TC_TBL* p_tbl) {
    235   tMCA_DCB* p_dcb;
    236   const tL2CAP_FCR_OPTS* p_opt;
    237   tMCA_FCS_OPT fcs = MCA_FCS_NONE;
    238 
    239   if (p_tbl->tcid == MCA_CTRL_TCID) {
    240     p_opt = &mca_l2c_fcr_opts_def;
    241   } else {
    242     p_dcb = mca_dcb_by_hdl(p_tbl->cb_idx);
    243     if (p_dcb) {
    244       p_opt = &p_dcb->p_chnl_cfg->fcr_opt;
    245       fcs = p_dcb->p_chnl_cfg->fcs;
    246     }
    247   }
    248   memset(p_cfg, 0, sizeof(tL2CAP_CFG_INFO));
    249   p_cfg->mtu_present = true;
    250   p_cfg->mtu = p_tbl->my_mtu;
    251   p_cfg->fcr_present = true;
    252   memcpy(&p_cfg->fcr, p_opt, sizeof(tL2CAP_FCR_OPTS));
    253   if (fcs & MCA_FCS_PRESNT_MASK) {
    254     p_cfg->fcs_present = true;
    255     p_cfg->fcs = (fcs & MCA_FCS_USE_MASK);
    256   }
    257 }
    258 
    259 /*******************************************************************************
    260  *
    261  * Function         mca_tc_close_ind
    262  *
    263  * Description      This function is called by the L2CAP interface when the
    264  *                  L2CAP channel is closed.  It looks up the CCB or DCB for
    265  *                  the channel and sends it a close event.  The reason
    266  *                  parameter is the same value passed by the L2CAP
    267  *                  callback function.
    268  *
    269  * Returns          Nothing.
    270  *
    271  ******************************************************************************/
    272 void mca_tc_close_ind(tMCA_TC_TBL* p_tbl, uint16_t reason) {
    273   tMCA_CCB* p_ccb;
    274   tMCA_DCB* p_dcb;
    275 
    276   MCA_TRACE_DEBUG("%s() - tcid: %d, cb_idx:%d, old: %d", __func__, p_tbl->tcid,
    277                   p_tbl->cb_idx, p_tbl->state);
    278 
    279   /* Check if the transport channel is in use */
    280   if (p_tbl->state == MCA_TC_ST_UNUSED) return;
    281 
    282   tMCA_CLOSE close;
    283 
    284   close.param = MCA_ACP;
    285   close.reason = reason;
    286   close.lcid = p_tbl->lcid;
    287 
    288   /* clear mca_tc_tbl entry */
    289   if (p_tbl->cfg_flags & MCA_L2C_CFG_DISCN_INT) close.param = MCA_INT;
    290   p_tbl->cfg_flags = 0;
    291   p_tbl->peer_mtu = L2CAP_DEFAULT_MTU;
    292 
    293   /* if control channel, notify ccb of the channel close */
    294   if (p_tbl->tcid == MCA_CTRL_TCID) {
    295     p_ccb = mca_ccb_by_hdl((tMCA_CL)p_tbl->cb_idx);
    296     tMCA_CCB_EVT mca_ccb_evt;
    297     mca_ccb_evt.close = close;
    298     mca_ccb_event(p_ccb, MCA_CCB_LL_CLOSE_EVT, &mca_ccb_evt);
    299   } else {
    300     /* notify dcb of the channel close */
    301     p_dcb = mca_dcb_by_hdl(p_tbl->cb_idx);
    302     if (p_dcb != NULL) {
    303       tMCA_DCB_EVT mca_dcb_evt;
    304       mca_dcb_evt.close = close;
    305       mca_dcb_event(p_dcb, MCA_DCB_TC_CLOSE_EVT, &mca_dcb_evt);
    306     }
    307   }
    308   p_tbl->state = MCA_TC_ST_UNUSED;
    309 }
    310 
    311 /*******************************************************************************
    312  *
    313  * Function         mca_tc_open_ind
    314  *
    315  * Description      This function is called by the L2CAP interface when
    316  *                  the L2CAP channel is opened.  It looks up the CCB or DCB
    317  *                  for the channel and sends it an open event.
    318  *
    319  * Returns          Nothing.
    320  *
    321  ******************************************************************************/
    322 void mca_tc_open_ind(tMCA_TC_TBL* p_tbl) {
    323   tMCA_CCB* p_ccb;
    324   tMCA_DCB* p_dcb;
    325   tMCA_OPEN open;
    326 
    327   MCA_TRACE_DEBUG("mca_tc_open_ind tcid: %d, cb_idx: %d", p_tbl->tcid,
    328                   p_tbl->cb_idx);
    329   p_tbl->state = MCA_TC_ST_OPEN;
    330 
    331   open.peer_mtu = p_tbl->peer_mtu;
    332   open.lcid = p_tbl->lcid;
    333   /* use param to indicate the role of connection.
    334    * MCA_ACP, if ACP */
    335   open.param = MCA_INT;
    336   if (p_tbl->cfg_flags & MCA_L2C_CFG_CONN_ACP) {
    337     open.param = MCA_ACP;
    338   }
    339 
    340   /* if control channel, notify ccb that the channel is open */
    341   if (p_tbl->tcid == MCA_CTRL_TCID) {
    342     p_ccb = mca_ccb_by_hdl((tMCA_CL)p_tbl->cb_idx);
    343     tMCA_CCB_EVT mca_ccb_evt;
    344     mca_ccb_evt.open = open;
    345     mca_ccb_event(p_ccb, MCA_CCB_LL_OPEN_EVT, &mca_ccb_evt);
    346   } else {
    347     /* must be data channel, notify dcb that the channel is open */
    348     p_dcb = mca_dcb_by_hdl(p_tbl->cb_idx);
    349 
    350     /* put lcid in event data */
    351     if (p_dcb != NULL) {
    352       tMCA_DCB_EVT mca_dcb_evt;
    353       mca_dcb_evt.open = open;
    354       mca_dcb_event(p_dcb, MCA_DCB_TC_OPEN_EVT, &mca_dcb_evt);
    355     }
    356   }
    357 }
    358 
    359 /*******************************************************************************
    360  *
    361  * Function         mca_tc_cong_ind
    362  *
    363  * Description      This function is called by the L2CAP interface layer when
    364  *                  L2CAP calls the congestion callback.  It looks up the CCB
    365  *                  or DCB for the channel and sends it a congestion event.
    366  *                  The is_congested parameter is the same value passed by
    367  *                  the L2CAP callback function.
    368  *
    369  *
    370  * Returns          Nothing.
    371  *
    372  ******************************************************************************/
    373 void mca_tc_cong_ind(tMCA_TC_TBL* p_tbl, bool is_congested) {
    374   tMCA_CCB* p_ccb;
    375   tMCA_DCB* p_dcb;
    376 
    377   MCA_TRACE_DEBUG("%s() - tcid: %d, cb_idx: %d", __func__, p_tbl->tcid,
    378                   p_tbl->cb_idx);
    379 
    380   /* if control channel, notify ccb of congestion */
    381   if (p_tbl->tcid == MCA_CTRL_TCID) {
    382     p_ccb = mca_ccb_by_hdl((tMCA_CL)p_tbl->cb_idx);
    383     tMCA_CCB_EVT mca_ccb_evt;
    384     mca_ccb_evt.llcong = is_congested;
    385     mca_ccb_event(p_ccb, MCA_CCB_LL_CONG_EVT, &mca_ccb_evt);
    386   } else {
    387     /* notify dcb that channel open */
    388     p_dcb = mca_dcb_by_hdl(p_tbl->cb_idx);
    389     if (p_dcb != NULL) {
    390       tMCA_DCB_EVT mca_dcb_evt;
    391       mca_dcb_evt.llcong = is_congested;
    392       mca_dcb_event(p_dcb, MCA_DCB_TC_CONG_EVT, &mca_dcb_evt);
    393     }
    394   }
    395 }
    396 
    397 /*******************************************************************************
    398  *
    399  * Function         mca_tc_data_ind
    400  *
    401  * Description      This function is called by the L2CAP interface layer when
    402  *                  incoming data is received from L2CAP.  It looks up the CCB
    403  *                  or DCB for the channel and routes the data accordingly.
    404  *
    405  * Returns          Nothing.
    406  *
    407  ******************************************************************************/
    408 void mca_tc_data_ind(tMCA_TC_TBL* p_tbl, BT_HDR* p_buf) {
    409   tMCA_CCB* p_ccb;
    410   tMCA_DCB* p_dcb;
    411   uint8_t event = MCA_CCB_MSG_RSP_EVT;
    412   uint8_t* p;
    413   uint8_t rej_rsp_code = MCA_RSP_SUCCESS;
    414 
    415   MCA_TRACE_DEBUG("%s: tcid: %d, cb_idx: %d", __func__, p_tbl->tcid,
    416                   p_tbl->cb_idx);
    417 
    418   /* if control channel, handle control message */
    419   if (p_tbl->tcid == MCA_CTRL_TCID) {
    420     p_ccb = mca_ccb_by_hdl((tMCA_CL)p_tbl->cb_idx);
    421     if (p_ccb) {
    422       p = (uint8_t*)(p_buf + 1) + p_buf->offset;
    423       /* all the request opcode has bit 0 set. response code has bit 0 clear */
    424       if ((*p) & 0x01) event = MCA_CCB_MSG_REQ_EVT;
    425 
    426       if (*p < MCA_NUM_STANDARD_OPCODE) {
    427         if (p_buf->len != mca_std_msg_len[*p]) {
    428           MCA_TRACE_ERROR("%s: opcode 0x%02x required len: %d, got len: %d",
    429                           __func__, *p, mca_std_msg_len[*p], p_buf->len);
    430           rej_rsp_code = MCA_RSP_BAD_PARAM;
    431         }
    432       } else if ((*p >= MCA_FIRST_SYNC_OP) && (*p <= MCA_LAST_SYNC_OP)) {
    433         MCA_TRACE_ERROR("%s: unsupported SYNC opcode: 0x%02x len:%d", __func__,
    434                         *p, p_buf->len);
    435         /* reject unsupported request */
    436         rej_rsp_code = MCA_RSP_NO_SUPPORT;
    437       } else {
    438         MCA_TRACE_ERROR("%s: bad opcode: 0x%02x len:%d", __func__, *p,
    439                         p_buf->len);
    440         /* reject unsupported request */
    441         rej_rsp_code = MCA_RSP_BAD_OPCODE;
    442       }
    443 
    444       p_buf->layer_specific = rej_rsp_code;
    445       /* forward the request/response to state machine */
    446       mca_ccb_event(p_ccb, event, (tMCA_CCB_EVT*)p_buf);
    447     } else {
    448       osi_free(p_buf);
    449     }
    450   } else {
    451     /* send event to dcb */
    452     p_dcb = mca_dcb_by_hdl(p_tbl->cb_idx);
    453     if (p_dcb != NULL) {
    454       mca_dcb_event(p_dcb, MCA_DCB_TC_DATA_EVT, (tMCA_DCB_EVT*)p_buf);
    455     } else {
    456       osi_free(p_buf);
    457     }
    458   }
    459 }
    460 
    461 /*******************************************************************************
    462  *
    463  * Function         mca_rcb_alloc
    464  *
    465  * Description      This function allocates a registration control block.
    466  *                  If no free RCB is available, it returns NULL.
    467  *
    468  * Returns          tMCA_RCB *
    469  *
    470  ******************************************************************************/
    471 tMCA_RCB* mca_rcb_alloc(tMCA_REG* p_reg) {
    472   int i;
    473   tMCA_RCB* p_rcb = NULL;
    474 
    475   for (i = 0; i < MCA_NUM_REGS; i++) {
    476     if (mca_cb.rcb[i].p_cback == NULL) {
    477       p_rcb = &mca_cb.rcb[i];
    478       memcpy(&p_rcb->reg, p_reg, sizeof(tMCA_REG));
    479       break;
    480     }
    481   }
    482   return p_rcb;
    483 }
    484 
    485 /*******************************************************************************
    486  *
    487  * Function         mca_rcb_dealloc
    488  *
    489  * Description      This function deallocates the RCB with the given handle.
    490  *
    491  * Returns          void.
    492  *
    493  ******************************************************************************/
    494 void mca_rcb_dealloc(tMCA_HANDLE handle) {
    495   int i;
    496   bool done = true;
    497   tMCA_RCB* p_rcb;
    498   tMCA_CCB* p_ccb;
    499 
    500   if (handle && (handle <= MCA_NUM_REGS)) {
    501     handle--;
    502     p_rcb = &mca_cb.rcb[handle];
    503     if (p_rcb->p_cback) {
    504       p_ccb = &mca_cb.ccb[handle * MCA_NUM_LINKS];
    505       /* check if all associated CCB are disconnected */
    506       for (i = 0; i < MCA_NUM_LINKS; i++, p_ccb++) {
    507         if (p_ccb->p_rcb) {
    508           done = false;
    509           mca_ccb_event(p_ccb, MCA_CCB_API_DISCONNECT_EVT, NULL);
    510         }
    511       }
    512 
    513       if (done) {
    514         memset(p_rcb, 0, sizeof(tMCA_RCB));
    515         MCA_TRACE_DEBUG("%s() - reset MCA_RCB index=%d", __func__, handle);
    516       }
    517     }
    518   }
    519 }
    520 
    521 /*******************************************************************************
    522  *
    523  * Function         mca_rcb_to_handle
    524  *
    525  * Description      This function converts a pointer to an RCB to
    526  *                  a handle (tMCA_HANDLE).  It returns the handle.
    527  *
    528  * Returns          void.
    529  *
    530  ******************************************************************************/
    531 tMCA_HANDLE mca_rcb_to_handle(tMCA_RCB* p_rcb) {
    532   return (uint8_t)(p_rcb - mca_cb.rcb + 1);
    533 }
    534 
    535 /*******************************************************************************
    536  *
    537  * Function         mca_rcb_by_handle
    538  *
    539  * Description      This function finds the RCB for a handle (tMCA_HANDLE).
    540  *                  It returns a pointer to the RCB.  If no RCB matches the
    541  *                  handle it returns NULL.
    542  *
    543  * Returns          tMCA_RCB *
    544  *
    545  ******************************************************************************/
    546 tMCA_RCB* mca_rcb_by_handle(tMCA_HANDLE handle) {
    547   tMCA_RCB* p_rcb = NULL;
    548 
    549   if (handle && (handle <= MCA_NUM_REGS) && mca_cb.rcb[handle - 1].p_cback) {
    550     p_rcb = &mca_cb.rcb[handle - 1];
    551   }
    552   return p_rcb;
    553 }
    554 
    555 /*******************************************************************************
    556  *
    557  * Function         mca_is_valid_dep_id
    558  *
    559  * Description      This function checks if the given dep_id is valid.
    560  *
    561  * Returns          true, if this is a valid local dep_id
    562  *
    563  ******************************************************************************/
    564 bool mca_is_valid_dep_id(tMCA_RCB* p_rcb, tMCA_DEP dep) {
    565   bool valid = false;
    566   if (dep < MCA_NUM_DEPS && p_rcb->dep[dep].p_data_cback) {
    567     valid = true;
    568   }
    569   return valid;
    570 }
    571