1 /******************************************************************************
3 * Copyright (C) 2003-2016 Broadcom Corporation
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:
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 ******************************************************************************/
19 /*****************************************************************************
21 * Name: avct_bcb_act.cc
23 * Description: This module contains action functions of the browsing control
26 *****************************************************************************/
32 #include "bt_target.h"
35 #include "osi/include/osi.h"
37 /* action function list */
38 const tAVCT_BCB_ACTION avct_bcb_action[] = {
39 avct_bcb_chnl_open, /* AVCT_LCB_CHNL_OPEN */
40 avct_bcb_chnl_disc, /* AVCT_LCB_CHNL_DISC */
41 avct_bcb_send_msg, /* AVCT_LCB_SEND_MSG */
42 avct_bcb_open_ind, /* AVCT_LCB_OPEN_IND */
43 avct_bcb_open_fail, /* AVCT_LCB_OPEN_FAIL */
44 avct_bcb_close_ind, /* AVCT_LCB_CLOSE_IND */
45 avct_bcb_close_cfm, /* AVCT_LCB_CLOSE_CFM */
46 avct_bcb_msg_ind, /* AVCT_LCB_MSG_IND */
47 avct_bcb_cong_ind, /* AVCT_LCB_CONG_IND */
48 avct_bcb_bind_conn, /* AVCT_LCB_BIND_CONN */
49 avct_bcb_bind_fail, /* AVCT_LCB_BIND_FAIL */
50 avct_bcb_unbind_disc, /* AVCT_LCB_UNBIND_DISC */
51 avct_bcb_chk_disc, /* AVCT_LCB_CHK_DISC */
52 avct_bcb_discard_msg, /* AVCT_LCB_DISCARD_MSG */
53 avct_bcb_dealloc, /* AVCT_LCB_DEALLOC */
54 avct_bcb_free_msg_ind /* AVCT_LCB_FREE_MSG_IND */
57 /*******************************************************************************
59 * Function avct_bcb_msg_asmbl
61 * Description Reassemble incoming message.
64 * Returns Pointer to reassembled message; NULL if no message
67 ******************************************************************************/
68 static BT_HDR* avct_bcb_msg_asmbl(UNUSED_ATTR tAVCT_BCB* p_bcb, BT_HDR* p_buf) {
72 if (p_buf->len == 0) {
73 osi_free_and_reset((void**)&p_buf);
74 android_errorWriteLog(0x534e4554, "79944113");
78 /* parse the message header */
79 p = (uint8_t*)(p_buf + 1) + p_buf->offset;
80 pkt_type = AVCT_PKT_TYPE(p);
82 /* must be single packet - can not fragment */
83 if (pkt_type != AVCT_PKT_TYPE_SINGLE) {
84 osi_free_and_reset((void**)&p_buf);
85 AVCT_TRACE_WARNING("Pkt type=%d - fragmentation not allowed. drop it",
91 /*******************************************************************************
93 * Function avct_bcb_chnl_open
95 * Description Open L2CAP channel to peer
100 ******************************************************************************/
101 void avct_bcb_chnl_open(tAVCT_BCB* p_bcb, UNUSED_ATTR tAVCT_LCB_EVT* p_data) {
102 uint16_t result = AVCT_RESULT_FAIL;
103 tAVCT_LCB* p_lcb = avct_lcb_by_bcb(p_bcb);
104 tL2CAP_ERTM_INFO ertm_info;
106 BTM_SetOutService(p_lcb->peer_addr, BTM_SEC_SERVICE_AVCTP_BROWSE, 0);
108 /* Set the FCR options: Browsing channel mandates ERTM */
109 ertm_info.preferred_mode = avct_l2c_br_fcr_opts_def.mode;
110 ertm_info.allowed_modes = L2CAP_FCR_CHAN_OPT_ERTM;
111 ertm_info.user_rx_buf_size = BT_DEFAULT_BUFFER_SIZE;
112 ertm_info.user_tx_buf_size = BT_DEFAULT_BUFFER_SIZE;
113 ertm_info.fcr_rx_buf_size = BT_DEFAULT_BUFFER_SIZE;
114 ertm_info.fcr_tx_buf_size = BT_DEFAULT_BUFFER_SIZE;
116 /* call l2cap connect req */
117 p_bcb->ch_state = AVCT_CH_CONN;
119 L2CA_ErtmConnectReq(AVCT_BR_PSM, p_lcb->peer_addr, &ertm_info);
120 if (p_bcb->ch_lcid == 0) {
121 /* if connect req failed, send ourselves close event */
122 tAVCT_LCB_EVT avct_lcb_evt;
123 avct_lcb_evt.result = result;
124 avct_bcb_event(p_bcb, AVCT_LCB_LL_CLOSE_EVT, &avct_lcb_evt);
128 /*******************************************************************************
130 * Function avct_bcb_unbind_disc
132 * Description call callback with disconnect event.
137 ******************************************************************************/
138 void avct_bcb_unbind_disc(UNUSED_ATTR tAVCT_BCB* p_bcb, tAVCT_LCB_EVT* p_data) {
139 p_data->p_ccb->p_bcb = NULL;
140 (*p_data->p_ccb->cc.p_ctrl_cback)(avct_ccb_to_idx(p_data->p_ccb),
141 AVCT_BROWSE_DISCONN_CFM_EVT, 0, NULL);
144 /*******************************************************************************
146 * Function avct_bcb_open_ind
148 * Description Handle an LL_OPEN event.
149 * For the allocated ccb already bound to the bcb, send a
150 * connect event. For the unbound ccb with a new PID, bind that
151 * ccb to the bcb with the same bd_addr and send a connect
157 ******************************************************************************/
158 void avct_bcb_open_ind(tAVCT_BCB* p_bcb, tAVCT_LCB_EVT* p_data) {
159 tAVCT_CCB* p_ccb = &avct_cb.ccb[0];
160 tAVCT_CCB* p_ccb_bind = NULL;
164 for (int idx = 0; idx < AVCT_NUM_CONN; idx++, p_ccb++) {
165 /* if ccb allocated and */
166 if (p_ccb->allocated) {
167 /* if bound to this bcb send connect confirm event */
168 if (p_ccb->p_bcb == p_bcb) {
171 p_ccb->cc.p_ctrl_cback(avct_ccb_to_idx(p_ccb), AVCT_BROWSE_CONN_CFM_EVT,
172 0, &p_ccb->p_lcb->peer_addr);
174 /* if unbound acceptor and lcb allocated and bd_addr are the same for bcb
176 else if ((p_ccb->p_bcb == NULL) && (p_ccb->cc.role == AVCT_ACP) &&
177 (p_ccb->p_lcb != NULL) &&
178 p_bcb->peer_addr == p_ccb->p_lcb->peer_addr) {
179 /* bind bcb to ccb and send connect ind event */
182 p_ccb->p_bcb = p_bcb;
183 p_ccb->cc.p_ctrl_cback(avct_ccb_to_idx(p_ccb), AVCT_BROWSE_CONN_IND_EVT,
184 0, &p_ccb->p_lcb->peer_addr);
189 /* if no ccbs bound to this lcb, disconnect */
191 avct_bcb_event(p_bcb, AVCT_LCB_INT_CLOSE_EVT, p_data);
195 if (!p_bcb->p_tx_msg || !p_ccb_bind) {
199 ul_msg.p_buf = p_bcb->p_tx_msg;
200 ul_msg.p_ccb = p_ccb_bind;
201 ul_msg.label = (uint8_t)(p_bcb->p_tx_msg->layer_specific & 0xFF);
202 ul_msg.cr = (uint8_t)((p_bcb->p_tx_msg->layer_specific & 0xFF00) >> 8);
203 p_bcb->p_tx_msg->layer_specific = AVCT_DATA_BROWSE;
204 p_bcb->p_tx_msg = NULL;
206 /* send msg event to bcb */
207 tAVCT_LCB_EVT avct_lcb_evt;
208 avct_lcb_evt.ul_msg = ul_msg;
209 avct_bcb_event(p_bcb, AVCT_LCB_UL_MSG_EVT, &avct_lcb_evt);
212 /*******************************************************************************
214 * Function avct_bcb_open_fail
216 * Description L2CAP channel open attempt failed. Mark the ccbs
222 ******************************************************************************/
223 void avct_bcb_open_fail(tAVCT_BCB* p_bcb, UNUSED_ATTR tAVCT_LCB_EVT* p_data) {
224 tAVCT_CCB* p_ccb = &avct_cb.ccb[0];
226 for (int idx = 0; idx < AVCT_NUM_CONN; idx++, p_ccb++) {
227 if (p_ccb->allocated && (p_ccb->p_bcb == p_bcb)) {
233 /*******************************************************************************
235 * Function avct_bcb_close_ind
237 * Description L2CAP channel closed by peer. Deallocate any initiator
238 * ccbs on this lcb and send disconnect ind event.
243 ******************************************************************************/
244 void avct_bcb_close_ind(tAVCT_BCB* p_bcb, UNUSED_ATTR tAVCT_LCB_EVT* p_data) {
245 tAVCT_CCB* p_ccb = &avct_cb.ccb[0];
246 tAVCT_LCB* p_lcb = avct_lcb_by_bcb(p_bcb);
248 for (int idx = 0; idx < AVCT_NUM_CONN; idx++, p_ccb++) {
249 if (p_ccb->allocated && (p_ccb->p_bcb == p_bcb)) {
250 if (p_ccb->cc.role == AVCT_INT) {
251 (*p_ccb->cc.p_ctrl_cback)(avct_ccb_to_idx(p_ccb),
252 AVCT_BROWSE_DISCONN_CFM_EVT, 0,
255 (*p_ccb->cc.p_ctrl_cback)(avct_ccb_to_idx(p_ccb),
256 AVCT_BROWSE_DISCONN_IND_EVT, 0, NULL);
263 /*******************************************************************************
265 * Function avct_bcb_close_cfm
267 * Description L2CAP channel closed by us. Deallocate any initiator
268 * ccbs on this lcb and send disconnect ind or cfm event.
273 ******************************************************************************/
274 void avct_bcb_close_cfm(tAVCT_BCB* p_bcb, tAVCT_LCB_EVT* p_data) {
275 tAVCT_CCB* p_ccb = &avct_cb.ccb[0];
277 /* Whether BCB initiated channel close */
278 bool ch_close = p_bcb->ch_close;
279 tAVCT_CTRL_CBACK* p_cback;
281 p_bcb->ch_close = false;
282 p_bcb->allocated = 0;
283 for (int idx = 0; idx < AVCT_NUM_CONN; idx++, p_ccb++) {
284 if (p_ccb->allocated && (p_ccb->p_bcb == p_bcb)) {
285 /* if this ccb initiated close send disconnect cfm otherwise ind */
287 event = AVCT_BROWSE_DISCONN_CFM_EVT;
289 event = AVCT_BROWSE_DISCONN_IND_EVT;
292 p_cback = p_ccb->cc.p_ctrl_cback;
294 if (p_ccb->p_lcb == NULL) avct_ccb_dealloc(p_ccb, AVCT_NO_EVT, 0, NULL);
295 (*p_cback)(avct_ccb_to_idx(p_ccb), event, p_data->result,
301 /*******************************************************************************
303 * Function avct_bcb_bind_conn
305 * Description Bind ccb to lcb and send connect cfm event.
310 ******************************************************************************/
311 void avct_bcb_bind_conn(tAVCT_BCB* p_bcb, tAVCT_LCB_EVT* p_data) {
312 tAVCT_LCB* p_lcb = avct_lcb_by_bcb(p_bcb);
313 p_data->p_ccb->p_bcb = p_bcb;
314 (*p_data->p_ccb->cc.p_ctrl_cback)(avct_ccb_to_idx(p_data->p_ccb),
315 AVCT_BROWSE_CONN_CFM_EVT, 0,
319 /*******************************************************************************
321 * Function avct_bcb_chk_disc
323 * Description A ccb wants to close; if it is the last ccb on this lcb,
324 * close channel. Otherwise just deallocate and call
330 ******************************************************************************/
331 void avct_bcb_chk_disc(tAVCT_BCB* p_bcb, tAVCT_LCB_EVT* p_data) {
332 p_bcb->ch_close = avct_bcb_get_last_ccb_index(p_bcb, p_data->p_ccb);
333 if (p_bcb->ch_close) {
334 avct_bcb_event(p_bcb, AVCT_LCB_INT_CLOSE_EVT, p_data);
338 avct_bcb_unbind_disc(p_bcb, p_data);
341 /*******************************************************************************
343 * Function avct_bcb_chnl_disc
345 * Description Disconnect L2CAP channel.
350 ******************************************************************************/
351 void avct_bcb_chnl_disc(tAVCT_BCB* p_bcb, UNUSED_ATTR tAVCT_LCB_EVT* p_data) {
352 L2CA_DisconnectReq(p_bcb->ch_lcid);
355 /*******************************************************************************
357 * Function avct_bcb_bind_fail
359 * Description Deallocate ccb and call callback with connect event
360 * with failure result.
365 ******************************************************************************/
366 void avct_bcb_bind_fail(UNUSED_ATTR tAVCT_BCB* p_bcb, tAVCT_LCB_EVT* p_data) {
367 p_data->p_ccb->p_bcb = NULL;
368 (*p_data->p_ccb->cc.p_ctrl_cback)(avct_ccb_to_idx(p_data->p_ccb),
369 AVCT_BROWSE_CONN_CFM_EVT, AVCT_RESULT_FAIL,
373 /*******************************************************************************
375 * Function avct_bcb_cong_ind
377 * Description Handle congestion indication from L2CAP.
382 ******************************************************************************/
383 void avct_bcb_cong_ind(tAVCT_BCB* p_bcb, tAVCT_LCB_EVT* p_data) {
384 tAVCT_CCB* p_ccb = &avct_cb.ccb[0];
386 tAVCT_LCB* p_lcb = avct_lcb_by_bcb(p_bcb);
390 (p_data->cong) ? AVCT_BROWSE_CONG_IND_EVT : AVCT_BROWSE_UNCONG_IND_EVT;
392 /* send event to all ccbs on this lcb */
393 for (int idx = 0; idx < AVCT_NUM_CONN; idx++, p_ccb++) {
394 if (p_ccb->allocated && (p_ccb->p_bcb == p_bcb)) {
395 (*p_ccb->cc.p_ctrl_cback)(avct_ccb_to_idx(p_ccb), event, 0,
401 /*******************************************************************************
403 * Function avct_bcb_discard_msg
405 * Description Discard a message sent in from the API.
410 ******************************************************************************/
411 void avct_bcb_discard_msg(tAVCT_BCB* p_bcb, tAVCT_LCB_EVT* p_data) {
412 osi_free_and_reset((void**)&p_bcb->p_tx_msg);
414 /* if control channel is up, save the message and open the browsing channel */
415 if (p_data->ul_msg.p_ccb->p_lcb == NULL) {
416 osi_free_and_reset((void**)&p_data->ul_msg.p_buf);
419 p_bcb->p_tx_msg = p_data->ul_msg.p_buf;
421 if (p_bcb->p_tx_msg) {
422 p_bcb->p_tx_msg->layer_specific =
423 (p_data->ul_msg.cr << 8) + p_data->ul_msg.label;
425 /* the channel is closed, opening or closing - open it again */
426 AVCT_TRACE_DEBUG("ch_state: %d, allocated:%d->%d", p_bcb->ch_state,
427 p_bcb->allocated, p_data->ul_msg.p_ccb->p_lcb->allocated);
428 p_bcb->allocated = p_data->ul_msg.p_ccb->p_lcb->allocated;
429 avct_bcb_event(p_bcb, AVCT_LCB_UL_BIND_EVT,
430 (tAVCT_LCB_EVT*)p_data->ul_msg.p_ccb);
434 /*******************************************************************************
436 * Function avct_bcb_send_msg
438 * Description Build and send an AVCTP message.
443 ******************************************************************************/
444 void avct_bcb_send_msg(tAVCT_BCB* p_bcb, tAVCT_LCB_EVT* p_data) {
445 uint16_t curr_msg_len;
446 uint8_t pkt_type = AVCT_PKT_TYPE_SINGLE;
452 curr_msg_len = p_data->ul_msg.p_buf->len;
454 /* initialize packet type and other stuff */
455 if (curr_msg_len > (p_bcb->peer_mtu - AVCT_HDR_LEN_SINGLE)) {
456 AVCT_TRACE_ERROR("%s msg len (%d) exceeds peer mtu(%d-%d)!!", __func__,
457 curr_msg_len, p_bcb->peer_mtu, AVCT_HDR_LEN_SINGLE);
458 osi_free_and_reset((void**)&p_data->ul_msg.p_buf);
463 hdr_len = avct_lcb_pkt_type_len[pkt_type];
464 p_buf = p_data->ul_msg.p_buf;
466 /* set up to build header */
467 p_buf->len += hdr_len;
468 p_buf->offset -= hdr_len;
469 p = (uint8_t*)(p_buf + 1) + p_buf->offset;
472 AVCT_BUILD_HDR(p, p_data->ul_msg.label, pkt_type, p_data->ul_msg.cr);
473 UINT16_TO_BE_STREAM(p, p_data->ul_msg.p_ccb->cc.pid);
475 p_buf->layer_specific = AVCT_DATA_BROWSE;
477 /* send message to L2CAP */
478 L2CA_DataWrite(p_bcb->ch_lcid, p_buf);
481 /*******************************************************************************
483 * Function avct_bcb_free_msg_ind
485 * Description Discard an incoming AVCTP message.
490 ******************************************************************************/
491 void avct_bcb_free_msg_ind(UNUSED_ATTR tAVCT_BCB* p_bcb,
492 tAVCT_LCB_EVT* p_data) {
493 if (p_data) osi_free_and_reset((void**)&p_data->p_buf);
496 /*******************************************************************************
498 * Function avct_bcb_msg_ind
500 * Description Handle an incoming AVCTP message.
505 ******************************************************************************/
506 void avct_bcb_msg_ind(tAVCT_BCB* p_bcb, tAVCT_LCB_EVT* p_data) {
508 uint8_t label, type, cr_ipid;
511 tAVCT_LCB* p_lcb = avct_lcb_by_bcb(p_bcb);
513 if ((p_data == NULL) || (p_data->p_buf == NULL)) {
514 AVCT_TRACE_WARNING("%s p_data is NULL, returning!", __func__);
518 /* this p_buf is to be reported through p_msg_cback. The layer_specific
519 * needs to be set properly to indicate that it is received through
520 * browsing channel */
521 p_data->p_buf->layer_specific = AVCT_DATA_BROWSE;
523 /* reassemble message; if no message available (we received a fragment) return
525 p_data->p_buf = avct_bcb_msg_asmbl(p_bcb, p_data->p_buf);
526 if (p_data->p_buf == NULL) {
530 if (p_data->p_buf->len < AVCT_HDR_LEN_SINGLE) {
531 AVCT_TRACE_WARNING("Invalid AVCTP packet length %d: must be at least %d",
532 p_data->p_buf->len, AVCT_HDR_LEN_SINGLE);
533 osi_free_and_reset((void**)&p_data->p_buf);
534 android_errorWriteLog(0x534e4554, "79944113");
538 p = (uint8_t*)(p_data->p_buf + 1) + p_data->p_buf->offset;
540 /* parse header byte */
541 AVCT_PARSE_HDR(p, label, type, cr_ipid);
543 /* check for invalid cr_ipid */
544 if (cr_ipid == AVCT_CR_IPID_INVALID) {
545 AVCT_TRACE_WARNING("Invalid cr_ipid", cr_ipid);
546 osi_free_and_reset((void**)&p_data->p_buf);
550 /* parse and lookup PID */
551 BE_STREAM_TO_UINT16(pid, p);
552 p_ccb = avct_lcb_has_pid(p_lcb, pid);
554 /* PID found; send msg up, adjust bt hdr and call msg callback */
555 p_data->p_buf->offset += AVCT_HDR_LEN_SINGLE;
556 p_data->p_buf->len -= AVCT_HDR_LEN_SINGLE;
557 (*p_ccb->cc.p_msg_cback)(avct_ccb_to_idx(p_ccb), label, cr_ipid,
562 /* PID not found; drop message */
563 AVCT_TRACE_WARNING("No ccb for PID=%x", pid);
564 osi_free_and_reset((void**)&p_data->p_buf);
566 /* if command send reject */
567 if (cr_ipid == AVCT_CMD) {
568 BT_HDR* p_buf = (BT_HDR*)osi_malloc(AVRC_CMD_BUF_SIZE);
569 p_buf->len = AVCT_HDR_LEN_SINGLE;
570 p_buf->offset = AVCT_MSG_OFFSET - AVCT_HDR_LEN_SINGLE;
571 p = (uint8_t*)(p_buf + 1) + p_buf->offset;
572 AVCT_BUILD_HDR(p, label, AVCT_PKT_TYPE_SINGLE, AVCT_REJ);
573 UINT16_TO_BE_STREAM(p, pid);
574 p_buf->layer_specific = AVCT_DATA_BROWSE;
575 L2CA_DataWrite(p_bcb->ch_lcid, p_buf);
579 /*******************************************************************************
581 * Function avct_bcb_dealloc
583 * Description Deallocate a browse control block.
588 ******************************************************************************/
589 void avct_bcb_dealloc(tAVCT_BCB* p_bcb, UNUSED_ATTR tAVCT_LCB_EVT* p_data) {
590 tAVCT_CCB* p_ccb = &avct_cb.ccb[0];
592 AVCT_TRACE_DEBUG("%s %d", __func__, p_bcb->allocated);
594 for (int idx = 0; idx < AVCT_NUM_CONN; idx++, p_ccb++) {
595 /* if ccb allocated and */
596 if ((p_ccb->allocated) && (p_ccb->p_bcb == p_bcb)) {
598 AVCT_TRACE_DEBUG("%s used by ccb: %d", __func__, idx);
603 /* the browsing channel is down. Check if we have pending messages */
604 osi_free_and_reset((void**)&p_bcb->p_tx_msg);
605 memset(p_bcb, 0, sizeof(tAVCT_BCB));
608 /*******************************************************************************
610 * Function avct_close_bcb
612 * Description this function is called right before LCB disconnects.
617 ******************************************************************************/
618 void avct_close_bcb(tAVCT_LCB* p_lcb, tAVCT_LCB_EVT* p_data) {
619 tAVCT_BCB* p_bcb = avct_bcb_by_lcb(p_lcb);
620 if (p_bcb->allocated) {
621 avct_bcb_event(p_bcb, AVCT_LCB_UL_UNBIND_EVT, p_data);
625 /*******************************************************************************
627 * Function avct_lcb_by_bcb
629 * Description This lookup function finds the lcb for a bcb.
631 * Returns pointer to the lcb.
633 ******************************************************************************/
634 tAVCT_LCB* avct_lcb_by_bcb(tAVCT_BCB* p_bcb) {
635 return &avct_cb.lcb[p_bcb->allocated - 1];
638 /*******************************************************************************
640 * Function avct_bcb_by_lcb
642 * Description This lookup function finds the bcb for a lcb.
644 * Returns pointer to the lcb.
646 ******************************************************************************/
647 tAVCT_BCB* avct_bcb_by_lcb(tAVCT_LCB* p_lcb) {
648 return &avct_cb.bcb[p_lcb->allocated - 1];
651 /*******************************************************************************
653 * Function avct_bcb_get_last_ccb_index
655 * Description See if given ccb is only one on the bcb.
658 * Returns 0, if ccb is last, (ccb index + 1) otherwise.
660 ******************************************************************************/
661 uint8_t avct_bcb_get_last_ccb_index(tAVCT_BCB* p_bcb, tAVCT_CCB* p_ccb_last) {
662 tAVCT_CCB* p_ccb = &avct_cb.ccb[0];
665 for (int i = 0; i < AVCT_NUM_CONN; i++, p_ccb++) {
666 if (p_ccb->allocated && (p_ccb->p_bcb == p_bcb)) {
667 if (p_ccb != p_ccb_last) return 0;
668 idx = (uint8_t)(i + 1);
674 /*******************************************************************************
676 * Function avct_bcb_by_lcid
678 * Description Find the BCB associated with the L2CAP LCID
681 * Returns pointer to the lcb, or NULL if none found.
683 ******************************************************************************/
684 tAVCT_BCB* avct_bcb_by_lcid(uint16_t lcid) {
685 tAVCT_BCB* p_bcb = &avct_cb.bcb[0];
688 for (idx = 0; idx < AVCT_NUM_LINKS; idx++, p_bcb++) {
689 if (p_bcb->allocated && (p_bcb->ch_lcid == lcid)) {
695 AVCT_TRACE_WARNING("No bcb for lcid %x", lcid);