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