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