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