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 *******************************************************************************/
mca_ccb_rsp_tout(tMCA_CCB * p_ccb,tMCA_CCB_EVT * p_data)48 void 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 *******************************************************************************/
mca_ccb_report_event(tMCA_CCB * p_ccb,UINT8 event,tMCA_CTRL * p_data)65 void 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 *******************************************************************************/
mca_ccb_free_msg(tMCA_CCB * p_ccb,tMCA_CCB_EVT * p_data)80 void 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 *******************************************************************************/
mca_ccb_snd_req(tMCA_CCB * p_ccb,tMCA_CCB_EVT * p_data)96 void 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 *******************************************************************************/
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 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 *******************************************************************************/
mca_ccb_do_disconn(tMCA_CCB * p_ccb,tMCA_CCB_EVT * p_data)215 void 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 *******************************************************************************/
mca_ccb_cong(tMCA_CCB * p_ccb,tMCA_CCB_EVT * p_data)232 void 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 *******************************************************************************/
mca_ccb_hdl_req(tMCA_CCB * p_ccb,tMCA_CCB_EVT * p_data)259 void 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 *******************************************************************************/
mca_ccb_hdl_rsp(tMCA_CCB * p_ccb,tMCA_CCB_EVT * p_data)460 void 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 *******************************************************************************/
mca_ccb_ll_open(tMCA_CCB * p_ccb,tMCA_CCB_EVT * p_data)561 void 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 *******************************************************************************/
mca_ccb_dl_open(tMCA_CCB * p_ccb,tMCA_CCB_EVT * p_data)580 void 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