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 Control Channel Action
22 *  Functions.
23 *
24 ******************************************************************************/
25#include <string.h>
26#include "bt_target.h"
27#include "gki.h"
28#include "btm_api.h"
29#include "mca_api.h"
30#include "mca_defs.h"
31#include "mca_int.h"
32
33
34#include  "btu.h"
35/*****************************************************************************
36** constants
37*****************************************************************************/
38/*******************************************************************************
39**
40** Function         mca_ccb_rsp_tout
41**
42** Description      This function processes the response timeout.
43**
44** Returns          void.
45**
46*******************************************************************************/
47void mca_ccb_rsp_tout(tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data)
48{
49   tMCA_CTRL   evt_data;
50   mca_ccb_report_event(p_ccb, MCA_RSP_TOUT_IND_EVT, &evt_data);
51}
52
53/*******************************************************************************
54**
55** Function         mca_ccb_report_event
56**
57** Description      This function reports the given event.
58**
59** Returns          void.
60**
61*******************************************************************************/
62void mca_ccb_report_event(tMCA_CCB *p_ccb, UINT8 event, tMCA_CTRL *p_data)
63{
64    if (p_ccb && p_ccb->p_rcb && p_ccb->p_rcb->p_cback)
65        (*p_ccb->p_rcb->p_cback)(mca_rcb_to_handle(p_ccb->p_rcb), mca_ccb_to_hdl(p_ccb), event, p_data);
66}
67
68/*******************************************************************************
69**
70** Function         mca_ccb_free_msg
71**
72** Description      This function frees the received message.
73**
74** Returns          void.
75**
76*******************************************************************************/
77void mca_ccb_free_msg(tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data)
78{
79    GKI_freebuf (p_data);
80}
81
82/*******************************************************************************
83**
84** Function         mca_ccb_snd_req
85**
86** Description      This function builds a request and sends it to the peer.
87**
88** Returns          void.
89**
90*******************************************************************************/
91void mca_ccb_snd_req(tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data)
92{
93    tMCA_CCB_MSG *p_msg = (tMCA_CCB_MSG *)p_data;
94    BT_HDR  *p_pkt;
95    UINT8   *p, *p_start;
96    BOOLEAN is_abort = FALSE;
97    tMCA_DCB *p_dcb;
98
99    MCA_TRACE_DEBUG2 ("mca_ccb_snd_req cong=%d req=%d", p_ccb->cong, p_msg->op_code);
100    /* check for abort request */
101    if ((p_ccb->status == MCA_CCB_STAT_PENDING) && (p_msg->op_code == MCA_OP_MDL_ABORT_REQ))
102    {
103        p_dcb = mca_dcb_by_hdl(p_ccb->p_tx_req->dcb_idx);
104        /* the Abort API does not have the associated mdl_id.
105         * Get the mdl_id in dcb to compose the request */
106        p_msg->mdl_id = p_dcb->mdl_id;
107        mca_dcb_event(p_dcb, MCA_DCB_API_CLOSE_EVT, NULL);
108        mca_free_buf ((void **)&p_ccb->p_tx_req);
109        p_ccb->status = MCA_CCB_STAT_NORM;
110        is_abort = TRUE;
111    }
112
113    /* no pending outgoing messages or it's an abort request for a pending data channel */
114    if ((!p_ccb->p_tx_req) || is_abort)
115    {
116        p_ccb->p_tx_req = p_msg;
117        if (!p_ccb->cong)
118        {
119            p_pkt = (BT_HDR *)GKI_getbuf (MCA_CTRL_MTU);
120            if (p_pkt)
121            {
122                p_pkt->offset = L2CAP_MIN_OFFSET;
123                p = p_start = (UINT8*)(p_pkt + 1) + L2CAP_MIN_OFFSET;
124                *p++ = p_msg->op_code;
125                UINT16_TO_BE_STREAM (p, p_msg->mdl_id);
126                if (p_msg->op_code == MCA_OP_MDL_CREATE_REQ)
127                {
128                    *p++ = p_msg->mdep_id;
129                    *p++ = p_msg->param;
130                }
131                p_msg->hdr.layer_specific = TRUE;   /* mark this message as sent */
132                p_pkt->len = p - p_start;
133                L2CA_DataWrite (p_ccb->lcid, p_pkt);
134                p_ccb->timer_entry.param = (TIMER_PARAM_TYPE) p_ccb;
135                btu_start_timer(&p_ccb->timer_entry, BTU_TTYPE_MCA_CCB_RSP, p_ccb->p_rcb->reg.rsp_tout);
136            }
137        }
138        /* else the L2CAP channel is congested. keep the message to be sent later */
139    }
140    else
141    {
142        MCA_TRACE_WARNING0 ("dropping api req");
143        GKI_freebuf (p_data);
144    }
145}
146
147/*******************************************************************************
148**
149** Function         mca_ccb_snd_rsp
150**
151** Description      This function builds a response and sends it to
152**                  the peer.
153**
154** Returns          void.
155**
156*******************************************************************************/
157void mca_ccb_snd_rsp(tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data)
158{
159    tMCA_CCB_MSG *p_msg = (tMCA_CCB_MSG *)p_data;
160    BT_HDR  *p_pkt;
161    UINT8   *p, *p_start;
162    BOOLEAN chk_mdl = FALSE;
163    tMCA_DCB    *p_dcb;
164
165    MCA_TRACE_DEBUG2 ("mca_ccb_snd_rsp cong=%d req=%d", p_ccb->cong, p_msg->op_code);
166    /* assume that API functions verified the parameters */
167    p_pkt = (BT_HDR *)GKI_getbuf (MCA_CTRL_MTU);
168    if (p_pkt)
169    {
170        p_pkt->offset = L2CAP_MIN_OFFSET;
171        p = p_start = (UINT8*)(p_pkt + 1) + L2CAP_MIN_OFFSET;
172        *p++ = p_msg->op_code;
173        *p++ = p_msg->rsp_code;
174        UINT16_TO_BE_STREAM (p, p_msg->mdl_id);
175        if (p_msg->op_code == MCA_OP_MDL_CREATE_RSP)
176        {
177            *p++ = p_msg->param;
178            chk_mdl = TRUE;
179        }
180        else if (p_msg->op_code == MCA_OP_MDL_RECONNECT_RSP)
181                chk_mdl = TRUE;
182
183        if (chk_mdl && p_msg->rsp_code == MCA_RSP_SUCCESS)
184        {
185            p_dcb = mca_dcb_by_hdl(p_msg->dcb_idx);
186            BTM_SetSecurityLevel(FALSE, "", BTM_SEC_SERVICE_MCAP_DATA, p_ccb->sec_mask,
187                p_ccb->p_rcb->reg.data_psm, BTM_SEC_PROTO_MCA, p_msg->dcb_idx);
188            p_ccb->status = MCA_CCB_STAT_PENDING;
189            /* set p_tx_req to block API_REQ/API_RSP before DL is up */
190            mca_free_buf ((void **)&p_ccb->p_tx_req);
191            p_ccb->p_tx_req = p_ccb->p_rx_msg;
192            p_ccb->p_rx_msg = NULL;
193            p_ccb->p_tx_req->dcb_idx = p_msg->dcb_idx;
194        }
195        mca_free_buf ((void **)&p_ccb->p_rx_msg);
196        p_pkt->len = p - p_start;
197        L2CA_DataWrite (p_ccb->lcid, p_pkt);
198    }
199
200}
201
202/*******************************************************************************
203**
204** Function         mca_ccb_do_disconn
205**
206** Description      This function closes a control channel.
207**
208** Returns          void.
209**
210*******************************************************************************/
211void mca_ccb_do_disconn (tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data)
212{
213    mca_dcb_close_by_mdl_id (p_ccb, MCA_ALL_MDL_ID);
214    L2CA_DisconnectReq(p_ccb->lcid);
215}
216
217/*******************************************************************************
218**
219** Function         mca_ccb_cong
220**
221** Description      This function sets the congestion state for the CCB.
222**
223** Returns          void.
224**
225*******************************************************************************/
226void mca_ccb_cong(tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data)
227{
228    MCA_TRACE_DEBUG2 ("mca_ccb_cong cong=%d/%d", p_ccb->cong, p_data->llcong);
229    p_ccb->cong = p_data->llcong;
230    if (!p_ccb->cong)
231    {
232        /* if there's a held packet, send it now */
233        if (p_ccb->p_tx_req && !p_ccb->p_tx_req->hdr.layer_specific)
234        {
235            p_data = (tMCA_CCB_EVT *)p_ccb->p_tx_req;
236            p_ccb->p_tx_req = NULL;
237            mca_ccb_snd_req (p_ccb, p_data);
238        }
239    }
240}
241
242/*******************************************************************************
243**
244** Function         mca_ccb_hdl_req
245**
246** Description      This function is called when a MCAP request is received from
247**                  the peer. It calls the application callback function to
248**                  report the event.
249**
250** Returns          void.
251**
252*******************************************************************************/
253void mca_ccb_hdl_req(tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data)
254{
255    BT_HDR  *p_pkt = &p_data->hdr;
256    BT_HDR  *p_buf;
257    UINT8   *p, *p_start;
258    tMCA_DCB    *p_dcb;
259    tMCA_CTRL       evt_data;
260    tMCA_CCB_MSG    *p_rx_msg = NULL;
261    UINT8           reject_code = MCA_RSP_NO_RESOURCE;
262    BOOLEAN         send_rsp = FALSE;
263    BOOLEAN         check_req = FALSE;
264    UINT8           reject_opcode;
265
266    MCA_TRACE_DEBUG1 ("mca_ccb_hdl_req status:%d", p_ccb->status);
267    p_rx_msg = (tMCA_CCB_MSG *)p_pkt;
268    p = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
269    evt_data.hdr.op_code = *p++;
270    BE_STREAM_TO_UINT16 (evt_data.hdr.mdl_id, p);
271    reject_opcode = evt_data.hdr.op_code+1;
272
273    MCA_TRACE_DEBUG1 ("received mdl id: %d ", evt_data.hdr.mdl_id);
274    if (p_ccb->status == MCA_CCB_STAT_PENDING)
275    {
276        MCA_TRACE_DEBUG0 ("received req inpending state");
277        /* allow abort in pending state */
278        if ((p_ccb->status == MCA_CCB_STAT_PENDING) && (evt_data.hdr.op_code == MCA_OP_MDL_ABORT_REQ))
279        {
280            reject_code = MCA_RSP_SUCCESS;
281            send_rsp = TRUE;
282            /* clear the pending status */
283            p_ccb->status = MCA_CCB_STAT_NORM;
284            if (p_ccb->p_tx_req && ((p_dcb = mca_dcb_by_hdl(p_ccb->p_tx_req->dcb_idx))!= NULL))
285            {
286                mca_dcb_dealloc (p_dcb, NULL);
287                mca_free_buf ((void **)&p_ccb->p_tx_req);
288            }
289        }
290        else
291            reject_code = MCA_RSP_BAD_OP;
292    }
293    else if (p_ccb->p_rx_msg)
294    {
295        MCA_TRACE_DEBUG0 ("still handling prev req");
296        /* still holding previous message, reject this new one ?? */
297
298    }
299    else if (p_ccb->p_tx_req)
300    {
301        MCA_TRACE_DEBUG1 ("still waiting for a response ctrl_vpsm:0x%x", p_ccb->ctrl_vpsm);
302        /* sent a request; waiting for response */
303        if (p_ccb->ctrl_vpsm == 0)
304        {
305            MCA_TRACE_DEBUG0 ("local is ACP. accept the cmd from INT");
306            /* local is acceptor, need to handle the request */
307            check_req = TRUE;
308            reject_code = MCA_RSP_SUCCESS;
309            /* drop the previous request */
310            if ((p_ccb->p_tx_req->op_code == MCA_OP_MDL_CREATE_REQ) &&
311                ((p_dcb = mca_dcb_by_hdl(p_ccb->p_tx_req->dcb_idx)) != NULL))
312            {
313                mca_dcb_dealloc(p_dcb, NULL);
314            }
315            mca_free_buf ((void **)&p_ccb->p_tx_req);
316            mca_stop_timer(p_ccb);
317        }
318        else
319        {
320            /*  local is initiator, ignore the req */
321            GKI_freebuf (p_pkt);
322            return;
323        }
324    }
325    else if (p_pkt->layer_specific != MCA_RSP_SUCCESS)
326    {
327
328        reject_code = (UINT8)p_pkt->layer_specific;
329        if (((evt_data.hdr.op_code >= MCA_NUM_STANDARD_OPCODE) &&
330            (evt_data.hdr.op_code < MCA_FIRST_SYNC_OP)) ||
331            (evt_data.hdr.op_code > MCA_LAST_SYNC_OP))
332        {
333            /* invalid op code */
334            reject_opcode = MCA_OP_ERROR_RSP;
335            evt_data.hdr.mdl_id = 0;
336        }
337    }
338    else
339    {
340        check_req = TRUE;
341        reject_code = MCA_RSP_SUCCESS;
342    }
343
344    if (check_req)
345    {
346        if (reject_code == MCA_RSP_SUCCESS)
347        {
348            reject_code = MCA_RSP_BAD_MDL;
349            if (MCA_IS_VALID_MDL_ID(evt_data.hdr.mdl_id) ||
350                ((evt_data.hdr.mdl_id == MCA_ALL_MDL_ID) && (evt_data.hdr.op_code == MCA_OP_MDL_DELETE_REQ)))
351            {
352                reject_code = MCA_RSP_SUCCESS;
353                /* mdl_id is valid according to the spec */
354                switch (evt_data.hdr.op_code)
355                {
356                case MCA_OP_MDL_CREATE_REQ:
357                    evt_data.create_ind.dep_id = *p++;
358                    evt_data.create_ind.cfg = *p++;
359                    p_rx_msg->mdep_id = evt_data.create_ind.dep_id;
360                    if (!mca_is_valid_dep_id(p_ccb->p_rcb, p_rx_msg->mdep_id))
361                    {
362                        MCA_TRACE_ERROR0 ("not a valid local mdep id");
363                        reject_code = MCA_RSP_BAD_MDEP;
364                    }
365                    else if (mca_ccb_uses_mdl_id(p_ccb, evt_data.hdr.mdl_id))
366                    {
367                        MCA_TRACE_DEBUG0 ("the mdl_id is currently used in the CL(create)");
368                        mca_dcb_close_by_mdl_id(p_ccb, evt_data.hdr.mdl_id);
369                    }
370                    else
371                    {
372                        /* check if this dep still have MDL available */
373                        if (mca_dep_free_mdl(p_ccb, evt_data.create_ind.dep_id) == 0)
374                        {
375                            MCA_TRACE_ERROR0 ("the mdep is currently using max_mdl");
376                            reject_code = MCA_RSP_MDEP_BUSY;
377                        }
378                    }
379                    break;
380
381                case MCA_OP_MDL_RECONNECT_REQ:
382                    if (mca_ccb_uses_mdl_id(p_ccb, evt_data.hdr.mdl_id))
383                    {
384                        MCA_TRACE_ERROR0 ("the mdl_id is currently used in the CL(reconn)");
385                        reject_code = MCA_RSP_MDL_BUSY;
386                    }
387                    break;
388
389                case MCA_OP_MDL_ABORT_REQ:
390                    reject_code = MCA_RSP_BAD_OP;
391                    break;
392
393                case MCA_OP_MDL_DELETE_REQ:
394                    /* delete the associated mdl */
395                    mca_dcb_close_by_mdl_id(p_ccb, evt_data.hdr.mdl_id);
396                    send_rsp = TRUE;
397                    break;
398                }
399            }
400        }
401    }
402
403    if (((reject_code != MCA_RSP_SUCCESS) && (evt_data.hdr.op_code != MCA_OP_SYNC_INFO_IND))
404        || send_rsp)
405    {
406        p_buf = (BT_HDR *)GKI_getbuf (MCA_CTRL_MTU);
407        if (p_buf)
408        {
409            p_buf->offset = L2CAP_MIN_OFFSET;
410            p = p_start = (UINT8*)(p_buf + 1) + L2CAP_MIN_OFFSET;
411            *p++ = reject_opcode;
412            *p++ = reject_code;
413            UINT16_TO_BE_STREAM (p, evt_data.hdr.mdl_id);
414            /*
415            if (((*p_start) == MCA_OP_MDL_CREATE_RSP) && (reject_code == MCA_RSP_SUCCESS))
416            {
417                *p++ = evt_data.create_ind.cfg;
418            }
419            */
420
421            p_buf->len = p - p_start;
422            L2CA_DataWrite (p_ccb->lcid, p_buf);
423        }
424    }
425
426    if (reject_code == MCA_RSP_SUCCESS)
427    {
428        /* use the received GKI buffer to store information to double check response API */
429        p_rx_msg->op_code = evt_data.hdr.op_code;
430        p_rx_msg->mdl_id = evt_data.hdr.mdl_id;
431        p_ccb->p_rx_msg = p_rx_msg;
432        if (send_rsp)
433        {
434            GKI_freebuf (p_pkt);
435            p_ccb->p_rx_msg = NULL;
436        }
437        mca_ccb_report_event(p_ccb, evt_data.hdr.op_code, &evt_data);
438    }
439    else
440        GKI_freebuf (p_pkt);
441}
442
443/*******************************************************************************
444**
445** Function         mca_ccb_hdl_rsp
446**
447** Description      This function is called when a MCAP response is received from
448**                  the peer.  It calls the application callback function with
449**                  the results.
450**
451** Returns          void.
452**
453*******************************************************************************/
454void mca_ccb_hdl_rsp(tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data)
455{
456    BT_HDR  *p_pkt = &p_data->hdr;
457    UINT8   *p;
458    tMCA_CTRL   evt_data;
459    BOOLEAN     chk_mdl = FALSE;
460    tMCA_DCB    *p_dcb;
461    tMCA_RESULT result = MCA_BAD_HANDLE;
462    tMCA_TC_TBL *p_tbl;
463
464    if (p_ccb->p_tx_req)
465    {
466        /* verify that the received response matches the sent request */
467        p = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
468        evt_data.hdr.op_code = *p++;
469        if ((evt_data.hdr.op_code == 0) ||
470            ((p_ccb->p_tx_req->op_code + 1) == evt_data.hdr.op_code))
471        {
472            evt_data.rsp.rsp_code = *p++;
473            mca_stop_timer(p_ccb);
474            BE_STREAM_TO_UINT16 (evt_data.hdr.mdl_id, p);
475            if (evt_data.hdr.op_code == MCA_OP_MDL_CREATE_RSP)
476            {
477                evt_data.create_cfm.cfg = *p++;
478                chk_mdl = TRUE;
479            }
480            else if (evt_data.hdr.op_code == MCA_OP_MDL_RECONNECT_RSP)
481                    chk_mdl = TRUE;
482
483            if (chk_mdl)
484            {
485                p_dcb = mca_dcb_by_hdl(p_ccb->p_tx_req->dcb_idx);
486                if (evt_data.rsp.rsp_code == MCA_RSP_SUCCESS)
487                {
488                    if (evt_data.hdr.mdl_id != p_dcb->mdl_id)
489                    {
490                        MCA_TRACE_ERROR2 ("peer's mdl_id=%d != our mdl_id=%d", evt_data.hdr.mdl_id, p_dcb->mdl_id);
491                        /* change the response code to be an error */
492                        if (evt_data.rsp.rsp_code == MCA_RSP_SUCCESS)
493                        {
494                            evt_data.rsp.rsp_code = MCA_RSP_BAD_MDL;
495                            /* send Abort */
496                            p_ccb->status = MCA_CCB_STAT_PENDING;
497                            MCA_Abort(mca_ccb_to_hdl(p_ccb));
498                        }
499                    }
500                    else if (p_dcb->p_chnl_cfg)
501                    {
502                        /* the data channel configuration is known. Proceed with data channel initiation */
503                        BTM_SetSecurityLevel(TRUE, "", BTM_SEC_SERVICE_MCAP_DATA, p_ccb->sec_mask,
504                            p_ccb->data_vpsm, BTM_SEC_PROTO_MCA, p_ccb->p_tx_req->dcb_idx);
505                        p_dcb->lcid = mca_l2c_open_req(p_ccb->peer_addr, p_ccb->data_vpsm, p_dcb->p_chnl_cfg);
506                        if (p_dcb->lcid)
507                        {
508                            p_tbl = mca_tc_tbl_dalloc(p_dcb);
509                            if (p_tbl)
510                            {
511                                p_tbl->state = MCA_TC_ST_CONN;
512                                p_ccb->status = MCA_CCB_STAT_PENDING;
513                                result = MCA_SUCCESS;
514                            }
515                        }
516                    }
517                    else
518                    {
519                        /* mark this MCL as pending and wait for MCA_DataChnlCfg */
520                        p_ccb->status = MCA_CCB_STAT_PENDING;
521                        result = MCA_SUCCESS;
522                    }
523                }
524
525                if (result != MCA_SUCCESS && p_dcb)
526                {
527                    mca_dcb_dealloc(p_dcb, NULL);
528                }
529            } /* end of chk_mdl */
530
531            if (p_ccb->status != MCA_CCB_STAT_PENDING)
532                mca_free_buf ((void **)&p_ccb->p_tx_req);
533            mca_ccb_report_event(p_ccb, evt_data.hdr.op_code, &evt_data);
534        }
535        /* else a bad response is received */
536    }
537    else
538    {
539        /* not expecting any response. drop it */
540        MCA_TRACE_WARNING0 ("dropping received rsp (not expecting a response)");
541    }
542    GKI_freebuf (p_data);
543}
544
545/*******************************************************************************
546**
547** Function         mca_ccb_ll_open
548**
549** Description      This function is called to report MCA_CONNECT_IND_EVT event.
550**                  It also clears the congestion flag (ccb.cong).
551**
552** Returns          void.
553**
554*******************************************************************************/
555void mca_ccb_ll_open (tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data)
556{
557    tMCA_CTRL    evt_data;
558    p_ccb->cong  = FALSE;
559    evt_data.connect_ind.mtu = p_data->open.peer_mtu;
560    memcpy (evt_data.connect_ind.bd_addr, p_ccb->peer_addr, BD_ADDR_LEN);
561    mca_ccb_report_event (p_ccb, MCA_CONNECT_IND_EVT, &evt_data);
562}
563
564/*******************************************************************************
565**
566** Function         mca_ccb_dl_open
567**
568** Description      This function is called when data channel is open.
569**                  It clears p_tx_req to allow other message exchage on this CL.
570**
571** Returns          void.
572**
573*******************************************************************************/
574void mca_ccb_dl_open (tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data)
575{
576    mca_free_buf ((void **)&p_ccb->p_tx_req);
577    mca_free_buf ((void **)&p_ccb->p_rx_msg);
578    p_ccb->status = MCA_CCB_STAT_NORM;
579}
580
581