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