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