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
169    MCA_TRACE_DEBUG ("mca_ccb_snd_rsp cong=%d req=%d", p_ccb->cong, p_msg->op_code);
170    /* assume that API functions verified the parameters */
171    p_pkt = (BT_HDR *)GKI_getbuf (MCA_CTRL_MTU);
172    if (p_pkt)
173    {
174        p_pkt->offset = L2CAP_MIN_OFFSET;
175        p = p_start = (UINT8*)(p_pkt + 1) + L2CAP_MIN_OFFSET;
176        *p++ = p_msg->op_code;
177        *p++ = p_msg->rsp_code;
178        UINT16_TO_BE_STREAM (p, p_msg->mdl_id);
179        if (p_msg->op_code == MCA_OP_MDL_CREATE_RSP)
180        {
181            *p++ = p_msg->param;
182            chk_mdl = TRUE;
183        }
184        else if (p_msg->op_code == MCA_OP_MDL_RECONNECT_RSP)
185                chk_mdl = TRUE;
186
187        if (chk_mdl && p_msg->rsp_code == MCA_RSP_SUCCESS)
188        {
189            mca_dcb_by_hdl(p_msg->dcb_idx);
190            BTM_SetSecurityLevel(FALSE, "", BTM_SEC_SERVICE_MCAP_DATA, p_ccb->sec_mask,
191                p_ccb->p_rcb->reg.data_psm, BTM_SEC_PROTO_MCA, p_msg->dcb_idx);
192            p_ccb->status = MCA_CCB_STAT_PENDING;
193            /* set p_tx_req to block API_REQ/API_RSP before DL is up */
194            mca_free_buf ((void **)&p_ccb->p_tx_req);
195            p_ccb->p_tx_req = p_ccb->p_rx_msg;
196            p_ccb->p_rx_msg = NULL;
197            p_ccb->p_tx_req->dcb_idx = p_msg->dcb_idx;
198        }
199        mca_free_buf ((void **)&p_ccb->p_rx_msg);
200        p_pkt->len = p - p_start;
201        L2CA_DataWrite (p_ccb->lcid, p_pkt);
202    }
203
204}
205
206/*******************************************************************************
207**
208** Function         mca_ccb_do_disconn
209**
210** Description      This function closes a control channel.
211**
212** Returns          void.
213**
214*******************************************************************************/
215void mca_ccb_do_disconn (tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data)
216{
217    UNUSED(p_data);
218
219    mca_dcb_close_by_mdl_id (p_ccb, MCA_ALL_MDL_ID);
220    L2CA_DisconnectReq(p_ccb->lcid);
221}
222
223/*******************************************************************************
224**
225** Function         mca_ccb_cong
226**
227** Description      This function sets the congestion state for the CCB.
228**
229** Returns          void.
230**
231*******************************************************************************/
232void mca_ccb_cong(tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data)
233{
234    MCA_TRACE_DEBUG ("mca_ccb_cong cong=%d/%d", p_ccb->cong, p_data->llcong);
235    p_ccb->cong = p_data->llcong;
236    if (!p_ccb->cong)
237    {
238        /* if there's a held packet, send it now */
239        if (p_ccb->p_tx_req && !p_ccb->p_tx_req->hdr.layer_specific)
240        {
241            p_data = (tMCA_CCB_EVT *)p_ccb->p_tx_req;
242            p_ccb->p_tx_req = NULL;
243            mca_ccb_snd_req (p_ccb, p_data);
244        }
245    }
246}
247
248/*******************************************************************************
249**
250** Function         mca_ccb_hdl_req
251**
252** Description      This function is called when a MCAP request is received from
253**                  the peer. It calls the application callback function to
254**                  report the event.
255**
256** Returns          void.
257**
258*******************************************************************************/
259void mca_ccb_hdl_req(tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data)
260{
261    BT_HDR  *p_pkt = &p_data->hdr;
262    BT_HDR  *p_buf;
263    UINT8   *p, *p_start;
264    tMCA_DCB    *p_dcb;
265    tMCA_CTRL       evt_data;
266    tMCA_CCB_MSG    *p_rx_msg = NULL;
267    UINT8           reject_code = MCA_RSP_NO_RESOURCE;
268    BOOLEAN         send_rsp = FALSE;
269    BOOLEAN         check_req = FALSE;
270    UINT8           reject_opcode;
271
272    MCA_TRACE_DEBUG ("mca_ccb_hdl_req status:%d", p_ccb->status);
273    p_rx_msg = (tMCA_CCB_MSG *)p_pkt;
274    p = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
275    evt_data.hdr.op_code = *p++;
276    BE_STREAM_TO_UINT16 (evt_data.hdr.mdl_id, p);
277    reject_opcode = evt_data.hdr.op_code+1;
278
279    MCA_TRACE_DEBUG ("received mdl id: %d ", evt_data.hdr.mdl_id);
280    if (p_ccb->status == MCA_CCB_STAT_PENDING)
281    {
282        MCA_TRACE_DEBUG ("received req inpending state");
283        /* allow abort in pending state */
284        if ((p_ccb->status == MCA_CCB_STAT_PENDING) && (evt_data.hdr.op_code == MCA_OP_MDL_ABORT_REQ))
285        {
286            reject_code = MCA_RSP_SUCCESS;
287            send_rsp = TRUE;
288            /* clear the pending status */
289            p_ccb->status = MCA_CCB_STAT_NORM;
290            if (p_ccb->p_tx_req && ((p_dcb = mca_dcb_by_hdl(p_ccb->p_tx_req->dcb_idx))!= NULL))
291            {
292                mca_dcb_dealloc (p_dcb, NULL);
293                mca_free_buf ((void **)&p_ccb->p_tx_req);
294            }
295        }
296        else
297            reject_code = MCA_RSP_BAD_OP;
298    }
299    else if (p_ccb->p_rx_msg)
300    {
301        MCA_TRACE_DEBUG ("still handling prev req");
302        /* still holding previous message, reject this new one ?? */
303
304    }
305    else if (p_ccb->p_tx_req)
306    {
307        MCA_TRACE_DEBUG ("still waiting for a response ctrl_vpsm:0x%x", p_ccb->ctrl_vpsm);
308        /* sent a request; waiting for response */
309        if (p_ccb->ctrl_vpsm == 0)
310        {
311            MCA_TRACE_DEBUG ("local is ACP. accept the cmd from INT");
312            /* local is acceptor, need to handle the request */
313            check_req = TRUE;
314            reject_code = MCA_RSP_SUCCESS;
315            /* drop the previous request */
316            if ((p_ccb->p_tx_req->op_code == MCA_OP_MDL_CREATE_REQ) &&
317                ((p_dcb = mca_dcb_by_hdl(p_ccb->p_tx_req->dcb_idx)) != NULL))
318            {
319                mca_dcb_dealloc(p_dcb, NULL);
320            }
321            mca_free_buf ((void **)&p_ccb->p_tx_req);
322            mca_stop_timer(p_ccb);
323        }
324        else
325        {
326            /*  local is initiator, ignore the req */
327            GKI_freebuf (p_pkt);
328            return;
329        }
330    }
331    else if (p_pkt->layer_specific != MCA_RSP_SUCCESS)
332    {
333
334        reject_code = (UINT8)p_pkt->layer_specific;
335        if (((evt_data.hdr.op_code >= MCA_NUM_STANDARD_OPCODE) &&
336            (evt_data.hdr.op_code < MCA_FIRST_SYNC_OP)) ||
337            (evt_data.hdr.op_code > MCA_LAST_SYNC_OP))
338        {
339            /* invalid op code */
340            reject_opcode = MCA_OP_ERROR_RSP;
341            evt_data.hdr.mdl_id = 0;
342        }
343    }
344    else
345    {
346        check_req = TRUE;
347        reject_code = MCA_RSP_SUCCESS;
348    }
349
350    if (check_req)
351    {
352        if (reject_code == MCA_RSP_SUCCESS)
353        {
354            reject_code = MCA_RSP_BAD_MDL;
355            if (MCA_IS_VALID_MDL_ID(evt_data.hdr.mdl_id) ||
356                ((evt_data.hdr.mdl_id == MCA_ALL_MDL_ID) && (evt_data.hdr.op_code == MCA_OP_MDL_DELETE_REQ)))
357            {
358                reject_code = MCA_RSP_SUCCESS;
359                /* mdl_id is valid according to the spec */
360                switch (evt_data.hdr.op_code)
361                {
362                case MCA_OP_MDL_CREATE_REQ:
363                    evt_data.create_ind.dep_id = *p++;
364                    evt_data.create_ind.cfg = *p++;
365                    p_rx_msg->mdep_id = evt_data.create_ind.dep_id;
366                    if (!mca_is_valid_dep_id(p_ccb->p_rcb, p_rx_msg->mdep_id))
367                    {
368                        MCA_TRACE_ERROR ("not a valid local mdep id");
369                        reject_code = MCA_RSP_BAD_MDEP;
370                    }
371                    else if (mca_ccb_uses_mdl_id(p_ccb, evt_data.hdr.mdl_id))
372                    {
373                        MCA_TRACE_DEBUG ("the mdl_id is currently used in the CL(create)");
374                        mca_dcb_close_by_mdl_id(p_ccb, evt_data.hdr.mdl_id);
375                    }
376                    else
377                    {
378                        /* check if this dep still have MDL available */
379                        if (mca_dep_free_mdl(p_ccb, evt_data.create_ind.dep_id) == 0)
380                        {
381                            MCA_TRACE_ERROR ("the mdep is currently using max_mdl");
382                            reject_code = MCA_RSP_MDEP_BUSY;
383                        }
384                    }
385                    break;
386
387                case MCA_OP_MDL_RECONNECT_REQ:
388                    if (mca_ccb_uses_mdl_id(p_ccb, evt_data.hdr.mdl_id))
389                    {
390                        MCA_TRACE_ERROR ("the mdl_id is currently used in the CL(reconn)");
391                        reject_code = MCA_RSP_MDL_BUSY;
392                    }
393                    break;
394
395                case MCA_OP_MDL_ABORT_REQ:
396                    reject_code = MCA_RSP_BAD_OP;
397                    break;
398
399                case MCA_OP_MDL_DELETE_REQ:
400                    /* delete the associated mdl */
401                    mca_dcb_close_by_mdl_id(p_ccb, evt_data.hdr.mdl_id);
402                    send_rsp = TRUE;
403                    break;
404                }
405            }
406        }
407    }
408
409    if (((reject_code != MCA_RSP_SUCCESS) && (evt_data.hdr.op_code != MCA_OP_SYNC_INFO_IND))
410        || send_rsp)
411    {
412        p_buf = (BT_HDR *)GKI_getbuf (MCA_CTRL_MTU);
413        if (p_buf)
414        {
415            p_buf->offset = L2CAP_MIN_OFFSET;
416            p = p_start = (UINT8*)(p_buf + 1) + L2CAP_MIN_OFFSET;
417            *p++ = reject_opcode;
418            *p++ = reject_code;
419            UINT16_TO_BE_STREAM (p, evt_data.hdr.mdl_id);
420            /*
421            if (((*p_start) == MCA_OP_MDL_CREATE_RSP) && (reject_code == MCA_RSP_SUCCESS))
422            {
423                *p++ = evt_data.create_ind.cfg;
424            }
425            */
426
427            p_buf->len = p - p_start;
428            L2CA_DataWrite (p_ccb->lcid, p_buf);
429        }
430    }
431
432    if (reject_code == MCA_RSP_SUCCESS)
433    {
434        /* use the received GKI buffer to store information to double check response API */
435        p_rx_msg->op_code = evt_data.hdr.op_code;
436        p_rx_msg->mdl_id = evt_data.hdr.mdl_id;
437        p_ccb->p_rx_msg = p_rx_msg;
438        if (send_rsp)
439        {
440            GKI_freebuf (p_pkt);
441            p_ccb->p_rx_msg = NULL;
442        }
443        mca_ccb_report_event(p_ccb, evt_data.hdr.op_code, &evt_data);
444    }
445    else
446        GKI_freebuf (p_pkt);
447}
448
449/*******************************************************************************
450**
451** Function         mca_ccb_hdl_rsp
452**
453** Description      This function is called when a MCAP response is received from
454**                  the peer.  It calls the application callback function with
455**                  the results.
456**
457** Returns          void.
458**
459*******************************************************************************/
460void mca_ccb_hdl_rsp(tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data)
461{
462    BT_HDR  *p_pkt = &p_data->hdr;
463    UINT8   *p;
464    tMCA_CTRL   evt_data;
465    BOOLEAN     chk_mdl = FALSE;
466    tMCA_DCB    *p_dcb;
467    tMCA_RESULT result = MCA_BAD_HANDLE;
468    tMCA_TC_TBL *p_tbl;
469
470    if (p_ccb->p_tx_req)
471    {
472        /* verify that the received response matches the sent request */
473        p = (UINT8 *)(p_pkt + 1) + p_pkt->offset;
474        evt_data.hdr.op_code = *p++;
475        if ((evt_data.hdr.op_code == 0) ||
476            ((p_ccb->p_tx_req->op_code + 1) == evt_data.hdr.op_code))
477        {
478            evt_data.rsp.rsp_code = *p++;
479            mca_stop_timer(p_ccb);
480            BE_STREAM_TO_UINT16 (evt_data.hdr.mdl_id, p);
481            if (evt_data.hdr.op_code == MCA_OP_MDL_CREATE_RSP)
482            {
483                evt_data.create_cfm.cfg = *p++;
484                chk_mdl = TRUE;
485            }
486            else if (evt_data.hdr.op_code == MCA_OP_MDL_RECONNECT_RSP)
487                    chk_mdl = TRUE;
488
489            if (chk_mdl)
490            {
491                p_dcb = mca_dcb_by_hdl(p_ccb->p_tx_req->dcb_idx);
492                if (evt_data.rsp.rsp_code == MCA_RSP_SUCCESS)
493                {
494                    if (evt_data.hdr.mdl_id != p_dcb->mdl_id)
495                    {
496                        MCA_TRACE_ERROR ("peer's mdl_id=%d != our mdl_id=%d", evt_data.hdr.mdl_id, p_dcb->mdl_id);
497                        /* change the response code to be an error */
498                        if (evt_data.rsp.rsp_code == MCA_RSP_SUCCESS)
499                        {
500                            evt_data.rsp.rsp_code = MCA_RSP_BAD_MDL;
501                            /* send Abort */
502                            p_ccb->status = MCA_CCB_STAT_PENDING;
503                            MCA_Abort(mca_ccb_to_hdl(p_ccb));
504                        }
505                    }
506                    else if (p_dcb->p_chnl_cfg)
507                    {
508                        /* the data channel configuration is known. Proceed with data channel initiation */
509                        BTM_SetSecurityLevel(TRUE, "", BTM_SEC_SERVICE_MCAP_DATA, p_ccb->sec_mask,
510                            p_ccb->data_vpsm, BTM_SEC_PROTO_MCA, p_ccb->p_tx_req->dcb_idx);
511                        p_dcb->lcid = mca_l2c_open_req(p_ccb->peer_addr, p_ccb->data_vpsm, p_dcb->p_chnl_cfg);
512                        if (p_dcb->lcid)
513                        {
514                            p_tbl = mca_tc_tbl_dalloc(p_dcb);
515                            if (p_tbl)
516                            {
517                                p_tbl->state = MCA_TC_ST_CONN;
518                                p_ccb->status = MCA_CCB_STAT_PENDING;
519                                result = MCA_SUCCESS;
520                            }
521                        }
522                    }
523                    else
524                    {
525                        /* mark this MCL as pending and wait for MCA_DataChnlCfg */
526                        p_ccb->status = MCA_CCB_STAT_PENDING;
527                        result = MCA_SUCCESS;
528                    }
529                }
530
531                if (result != MCA_SUCCESS && p_dcb)
532                {
533                    mca_dcb_dealloc(p_dcb, NULL);
534                }
535            } /* end of chk_mdl */
536
537            if (p_ccb->status != MCA_CCB_STAT_PENDING)
538                mca_free_buf ((void **)&p_ccb->p_tx_req);
539            mca_ccb_report_event(p_ccb, evt_data.hdr.op_code, &evt_data);
540        }
541        /* else a bad response is received */
542    }
543    else
544    {
545        /* not expecting any response. drop it */
546        MCA_TRACE_WARNING ("dropping received rsp (not expecting a response)");
547    }
548    GKI_freebuf (p_data);
549}
550
551/*******************************************************************************
552**
553** Function         mca_ccb_ll_open
554**
555** Description      This function is called to report MCA_CONNECT_IND_EVT event.
556**                  It also clears the congestion flag (ccb.cong).
557**
558** Returns          void.
559**
560*******************************************************************************/
561void mca_ccb_ll_open (tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data)
562{
563    tMCA_CTRL    evt_data;
564    p_ccb->cong  = FALSE;
565    evt_data.connect_ind.mtu = p_data->open.peer_mtu;
566    memcpy (evt_data.connect_ind.bd_addr, p_ccb->peer_addr, BD_ADDR_LEN);
567    mca_ccb_report_event (p_ccb, MCA_CONNECT_IND_EVT, &evt_data);
568}
569
570/*******************************************************************************
571**
572** Function         mca_ccb_dl_open
573**
574** Description      This function is called when data channel is open.
575**                  It clears p_tx_req to allow other message exchage on this CL.
576**
577** Returns          void.
578**
579*******************************************************************************/
580void mca_ccb_dl_open (tMCA_CCB *p_ccb, tMCA_CCB_EVT *p_data)
581{
582    UNUSED(p_data);
583
584    mca_free_buf ((void **)&p_ccb->p_tx_req);
585    mca_free_buf ((void **)&p_ccb->p_rx_msg);
586    p_ccb->status = MCA_CCB_STAT_NORM;
587}
588
589