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