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