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