1 /******************************************************************************
2 *
3 * Copyright 2002-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 module contains the AVDTP adaption layer.
22 *
23 ******************************************************************************/
24
25 #define LOG_TAG "bluetooth-a2dp"
26
27 #include <bluetooth/log.h>
28 #include <string.h>
29
30 #include "avdt_api.h"
31 #include "avdt_int.h"
32 #include "internal_include/bt_target.h"
33 #include "l2c_api.h"
34 #include "l2cdefs.h"
35 #include "osi/include/allocator.h"
36 #include "stack/include/bt_hdr.h"
37 #include "stack/include/btm_sec_api_types.h"
38
39 using namespace bluetooth;
40
LookupAvdtpScb(const AvdtpTransportChannel & tc)41 AvdtpScb* AvdtpAdaptationLayer::LookupAvdtpScb(
42 const AvdtpTransportChannel& tc) {
43 if (tc.ccb_idx >= AVDT_NUM_LINKS) {
44 log::error("AvdtpScb entry not found: invalid ccb_idx:{}", tc.ccb_idx);
45 return nullptr;
46 }
47 if (tc.tcid >= AVDT_NUM_RT_TBL) {
48 log::error("AvdtpScb entry not found: invalid tcid:{}", tc.tcid);
49 return nullptr;
50 }
51 const AvdtpRoutingEntry& re = rt_tbl[tc.ccb_idx][tc.tcid];
52 log::verbose("ccb_idx:{} tcid:{} scb_hdl:{}", tc.ccb_idx, tc.tcid,
53 re.scb_hdl);
54 return avdt_scb_by_hdl(re.scb_hdl);
55 }
56
57 /*******************************************************************************
58 *
59 * Function avdt_ad_type_to_tcid
60 *
61 * Description Derives the TCID from the channel type and SCB.
62 *
63 *
64 * Returns TCID value.
65 *
66 ******************************************************************************/
avdt_ad_type_to_tcid(uint8_t type,AvdtpScb * p_scb)67 uint8_t avdt_ad_type_to_tcid(uint8_t type, AvdtpScb* p_scb) {
68 if (type == AVDT_CHAN_SIG) {
69 return 0;
70 }
71 // The SCB Handle is unique in the [1, AVDT_NUM_LINKS * AVDT_NUM_SEPS]
72 // range. The scb_idx computed here is the SCB index for the corresponding
73 // SEP, and it is in the range [0, AVDT_NUM_SEPS) for a particular link.
74 uint8_t scb_idx = (avdt_scb_to_hdl(p_scb) - 1) % AVDT_NUM_LINKS;
75 // There are AVDT_CHAN_NUM_TYPES channel types per SEP. Here we compute
76 // the type index (TCID) from the SEP index and the type itself.
77 uint8_t tcid = (scb_idx * (AVDT_CHAN_NUM_TYPES - 1)) + type;
78 log::verbose("type:{}, tcid: {}", type, tcid);
79 return tcid;
80 }
81
82 /*******************************************************************************
83 *
84 * Function avdt_ad_tcid_to_type
85 *
86 * Description Derives the channel type from the TCID.
87 *
88 *
89 * Returns Channel type value.
90 *
91 ******************************************************************************/
avdt_ad_tcid_to_type(uint8_t tcid)92 static uint8_t avdt_ad_tcid_to_type(uint8_t tcid) {
93 uint8_t type;
94
95 if (tcid == 0) {
96 type = AVDT_CHAN_SIG;
97 } else {
98 /* tcid translates to type based on number of channels, as follows:
99 ** only media channel : tcid=1,2,3,4,5,6... type=1,1,1,1,1,1...
100 ** media and report : tcid=1,2,3,4,5,6... type=1,2,1,2,1,2...
101 ** media, report, recov : tcid=1,2,3,4,5,6... type=1,2,3,1,2,3...
102 */
103 type = ((tcid + AVDT_CHAN_NUM_TYPES - 2) % (AVDT_CHAN_NUM_TYPES - 1)) + 1;
104 }
105 log::verbose("tcid: {}, type: {}", tcid, type);
106 return type;
107 }
108
109 /*******************************************************************************
110 *
111 * Function avdt_ad_init
112 *
113 * Description Initialize adaption layer.
114 *
115 *
116 * Returns Nothing.
117 *
118 ******************************************************************************/
avdt_ad_init(void)119 void avdt_ad_init(void) {
120 int i;
121 AvdtpTransportChannel* p_tbl = avdtp_cb.ad.tc_tbl;
122 avdtp_cb.ad.Reset();
123
124 /* make sure the peer_mtu is a valid value */
125 for (i = 0; i < AVDT_NUM_TC_TBL; i++, p_tbl++) {
126 p_tbl->peer_mtu = L2CAP_DEFAULT_MTU;
127 }
128 }
129
130 /*******************************************************************************
131 *
132 * Function avdt_ad_tc_tbl_by_st
133 *
134 * Description Find adaption layer transport channel table entry matching
135 * the given state.
136 *
137 *
138 * Returns Pointer to matching entry. For control channel it returns
139 * the matching entry. For media or other it returns the
140 * first matching entry (there could be more than one).
141 *
142 ******************************************************************************/
avdt_ad_tc_tbl_by_st(uint8_t type,AvdtpCcb * p_ccb,uint8_t state)143 AvdtpTransportChannel* avdt_ad_tc_tbl_by_st(uint8_t type, AvdtpCcb* p_ccb,
144 uint8_t state) {
145 int i;
146 AvdtpTransportChannel* p_tbl = avdtp_cb.ad.tc_tbl;
147 uint8_t ccb_idx;
148
149 if (p_ccb == NULL) {
150 /* resending security req */
151 for (i = 0; i < AVDT_NUM_TC_TBL; i++, p_tbl++) {
152 /* must be AVDT_CHAN_SIG - tcid always zero */
153 if ((p_tbl->tcid == 0) && (p_tbl->state == state)) {
154 break;
155 }
156 }
157 } else {
158 ccb_idx = avdt_ccb_to_idx(p_ccb);
159
160 for (i = 0; i < AVDT_NUM_TC_TBL; i++, p_tbl++) {
161 if (type == AVDT_CHAN_SIG) {
162 /* if control channel, tcid always zero */
163 if ((p_tbl->tcid == 0) && (p_tbl->ccb_idx == ccb_idx) &&
164 (p_tbl->state == state)) {
165 break;
166 }
167 } else {
168 /* if other channel, tcid is always > zero */
169 if ((p_tbl->tcid > 0) && (p_tbl->ccb_idx == ccb_idx) &&
170 (p_tbl->state == state)) {
171 break;
172 }
173 }
174 }
175 }
176
177 /* if nothing found return null */
178 if (i == AVDT_NUM_TC_TBL) {
179 p_tbl = NULL;
180 }
181
182 return p_tbl;
183 }
184
185 /*******************************************************************************
186 *
187 * Function avdt_ad_tc_tbl_by_lcid
188 *
189 * Description Find adaption layer transport channel table entry by LCID.
190 *
191 *
192 * Returns Pointer to entry.
193 *
194 ******************************************************************************/
avdt_ad_tc_tbl_by_lcid(uint16_t lcid)195 AvdtpTransportChannel* avdt_ad_tc_tbl_by_lcid(uint16_t lcid) {
196 if (avdtp_cb.ad.lcid_tbl.count(lcid) != 0) {
197 uint8_t idx = avdtp_cb.ad.lcid_tbl[lcid];
198 return &avdtp_cb.ad.tc_tbl[idx];
199 } else {
200 return nullptr;
201 }
202 }
203
204 /*******************************************************************************
205 *
206 * Function avdt_ad_tc_tbl_by_type
207 *
208 * Description This function retrieves the transport channel table entry
209 * for a particular channel.
210 *
211 *
212 * Returns Pointer to transport channel table entry.
213 *
214 ******************************************************************************/
avdt_ad_tc_tbl_by_type(uint8_t type,AvdtpCcb * p_ccb,AvdtpScb * p_scb)215 AvdtpTransportChannel* avdt_ad_tc_tbl_by_type(uint8_t type, AvdtpCcb* p_ccb,
216 AvdtpScb* p_scb) {
217 uint8_t tcid;
218 int i;
219 AvdtpTransportChannel* p_tbl = avdtp_cb.ad.tc_tbl;
220 uint8_t ccb_idx = avdt_ccb_to_idx(p_ccb);
221
222 /* get tcid from type, scb */
223 tcid = avdt_ad_type_to_tcid(type, p_scb);
224
225 for (i = 0; i < AVDT_NUM_TC_TBL; i++, p_tbl++) {
226 if ((p_tbl->tcid == tcid) && (p_tbl->ccb_idx == ccb_idx)) {
227 break;
228 }
229 }
230
231 log::assert_that(i != AVDT_NUM_TC_TBL, "assert failed: i != AVDT_NUM_TC_TBL");
232
233 return p_tbl;
234 }
235
236 /*******************************************************************************
237 *
238 * Function avdt_ad_tc_tbl_alloc
239 *
240 * Description Allocate an entry in the traffic channel table.
241 *
242 *
243 * Returns Pointer to entry.
244 *
245 ******************************************************************************/
avdt_ad_tc_tbl_alloc(AvdtpCcb * p_ccb)246 AvdtpTransportChannel* avdt_ad_tc_tbl_alloc(AvdtpCcb* p_ccb) {
247 int i;
248 AvdtpTransportChannel* p_tbl = avdtp_cb.ad.tc_tbl;
249
250 /* find next free entry in tc table */
251 for (i = 0; i < AVDT_NUM_TC_TBL; i++, p_tbl++) {
252 if (p_tbl->state == AVDT_AD_ST_UNUSED) {
253 break;
254 }
255 }
256
257 /* sanity check */
258 log::assert_that(i != AVDT_NUM_TC_TBL, "assert failed: i != AVDT_NUM_TC_TBL");
259
260 /* initialize entry */
261 p_tbl->peer_mtu = L2CAP_DEFAULT_MTU;
262 p_tbl->cfg_flags = 0;
263 p_tbl->ccb_idx = avdt_ccb_to_idx(p_ccb);
264 p_tbl->state = AVDT_AD_ST_IDLE;
265 return p_tbl;
266 }
267
268 /*******************************************************************************
269 *
270 * Function avdt_ad_tc_tbl_to_idx
271 *
272 * Description Convert a transport channel table entry to an index.
273 *
274 *
275 * Returns Index value.
276 *
277 ******************************************************************************/
avdt_ad_tc_tbl_to_idx(AvdtpTransportChannel * p_tbl)278 uint8_t avdt_ad_tc_tbl_to_idx(AvdtpTransportChannel* p_tbl) {
279 log::verbose("avdt_ad_tc_tbl_to_idx: {}", (long)(p_tbl - avdtp_cb.ad.tc_tbl));
280 /* use array arithmetic to determine index */
281 return (uint8_t)(p_tbl - avdtp_cb.ad.tc_tbl);
282 }
283
284 /*******************************************************************************
285 *
286 * Function avdt_ad_tc_close_ind
287 *
288 * Description This function is called by the L2CAP interface when the
289 * L2CAP channel is closed. It looks up the CCB or SCB for
290 * the channel and sends it a close event. The reason
291 * parameter is the same value passed by the L2CAP
292 * callback function.
293 *
294 *
295 * Returns Nothing.
296 *
297 ******************************************************************************/
avdt_ad_tc_close_ind(AvdtpTransportChannel * p_tbl)298 void avdt_ad_tc_close_ind(AvdtpTransportChannel* p_tbl) {
299 AvdtpCcb* p_ccb;
300 AvdtpScb* p_scb;
301 tAVDT_SCB_TC_CLOSE close;
302
303 close.old_tc_state = p_tbl->state;
304 /* clear avdt_ad_tc_tbl entry */
305 p_tbl->state = AVDT_AD_ST_UNUSED;
306 p_tbl->cfg_flags = 0;
307 p_tbl->peer_mtu = L2CAP_DEFAULT_MTU;
308
309 log::verbose("tcid: {}, old: {}", p_tbl->tcid, close.old_tc_state);
310 /* if signaling channel, notify ccb that channel open */
311 if (p_tbl->tcid == 0) {
312 p_ccb = avdt_ccb_by_idx(p_tbl->ccb_idx);
313 avdt_ccb_event(p_ccb, AVDT_CCB_LL_CLOSE_EVT, NULL);
314 return;
315 }
316 /* if media or other channel, notify scb that channel close */
317 /* look up scb in stream routing table by ccb, tcid */
318 p_scb = avdtp_cb.ad.LookupAvdtpScb(*p_tbl);
319 if (p_scb == nullptr) {
320 log::error("Cannot find AvdtScb entry: ccb_idx:{} tcid:{}", p_tbl->ccb_idx,
321 p_tbl->tcid);
322 return;
323 }
324 close.tcid = p_tbl->tcid;
325 close.type = avdt_ad_tcid_to_type(p_tbl->tcid);
326 tAVDT_SCB_EVT avdt_scb_evt;
327 avdt_scb_evt.close = close;
328 avdt_scb_event(p_scb, AVDT_SCB_TC_CLOSE_EVT, &avdt_scb_evt);
329 }
330
331 /*******************************************************************************
332 *
333 * Function avdt_ad_tc_open_ind
334 *
335 * Description This function is called by the L2CAP interface when
336 * the L2CAP channel is opened. It looks up the CCB or SCB
337 * for the channel and sends it an open event.
338 *
339 *
340 * Returns Nothing.
341 *
342 ******************************************************************************/
avdt_ad_tc_open_ind(AvdtpTransportChannel * p_tbl)343 void avdt_ad_tc_open_ind(AvdtpTransportChannel* p_tbl) {
344 AvdtpCcb* p_ccb;
345 AvdtpScb* p_scb;
346 tAVDT_OPEN open;
347 tAVDT_EVT_HDR evt;
348
349 log::verbose("p_tbl:{} state:{} ccb_idx:{} tcid:{} scb_hdl:{}",
350 fmt::ptr(p_tbl), p_tbl->state, p_tbl->ccb_idx, p_tbl->tcid,
351 avdtp_cb.ad.rt_tbl[p_tbl->ccb_idx][p_tbl->tcid].scb_hdl);
352
353 p_tbl->state = AVDT_AD_ST_OPEN;
354
355 /* if signaling channel, notify ccb that channel open */
356 if (p_tbl->tcid == 0) {
357 /* set the signal channel to use high priority within the ACL link */
358 if (!L2CA_SetTxPriority(
359 avdtp_cb.ad.rt_tbl[p_tbl->ccb_idx][AVDT_CHAN_SIG].lcid,
360 L2CAP_CHNL_PRIORITY_HIGH)) {
361 log::warn("Unable to set L2CAP transmit high priority cid:{}",
362 avdtp_cb.ad.rt_tbl[p_tbl->ccb_idx][AVDT_CHAN_SIG].lcid);
363 }
364
365 p_ccb = avdt_ccb_by_idx(p_tbl->ccb_idx);
366 /* use err_param to indicate the role of connection.
367 * AVDT_ACP, if ACP */
368 evt.err_param = AVDT_INT;
369 if (p_tbl->cfg_flags & AVDT_L2C_CFG_CONN_ACP) {
370 evt.err_param = AVDT_ACP;
371 }
372 tAVDT_CCB_EVT avdt_ccb_evt;
373 avdt_ccb_evt.msg.hdr = evt;
374 avdt_ccb_event(p_ccb, AVDT_CCB_LL_OPEN_EVT, &avdt_ccb_evt);
375 return;
376 }
377 /* if media or other channel, notify scb that channel open */
378 /* look up scb in stream routing table by ccb, tcid */
379 p_scb = avdtp_cb.ad.LookupAvdtpScb(*p_tbl);
380 if (p_scb == nullptr) {
381 log::error("Cannot find AvdtScb entry: ccb_idx:{} tcid:{}", p_tbl->ccb_idx,
382 p_tbl->tcid);
383 return;
384 }
385 /* put lcid in event data */
386 open.peer_mtu = p_tbl->peer_mtu;
387 open.lcid = avdtp_cb.ad.rt_tbl[p_tbl->ccb_idx][p_tbl->tcid].lcid;
388 open.hdr.err_code = avdt_ad_tcid_to_type(p_tbl->tcid);
389 tAVDT_SCB_EVT avdt_scb_evt;
390 avdt_scb_evt.open = open;
391 avdt_scb_event(p_scb, AVDT_SCB_TC_OPEN_EVT, &avdt_scb_evt);
392 }
393
394 /*******************************************************************************
395 *
396 * Function avdt_ad_tc_cong_ind
397 *
398 * Description This function is called by the L2CAP interface layer when
399 * L2CAP calls the congestion callback. It looks up the CCB
400 * or SCB for the channel and sends it a congestion event.
401 * The is_congested parameter is the same value passed by
402 * the L2CAP callback function.
403 *
404 *
405 * Returns Nothing.
406 *
407 ******************************************************************************/
avdt_ad_tc_cong_ind(AvdtpTransportChannel * p_tbl,bool is_congested)408 void avdt_ad_tc_cong_ind(AvdtpTransportChannel* p_tbl, bool is_congested) {
409 AvdtpCcb* p_ccb;
410 AvdtpScb* p_scb;
411
412 /* if signaling channel, notify ccb of congestion */
413 if (p_tbl->tcid == 0) {
414 p_ccb = avdt_ccb_by_idx(p_tbl->ccb_idx);
415 tAVDT_CCB_EVT avdt_ccb_evt;
416 avdt_ccb_evt.llcong = is_congested;
417 avdt_ccb_event(p_ccb, AVDT_CCB_LL_CONG_EVT, &avdt_ccb_evt);
418 return;
419 }
420 /* if media or other channel, notify scb that channel open */
421 /* look up scb in stream routing table by ccb, tcid */
422 p_scb = avdtp_cb.ad.LookupAvdtpScb(*p_tbl);
423 if (p_scb == nullptr) {
424 log::error("Cannot find AvdtScb entry: ccb_idx:{} tcid:{}", p_tbl->ccb_idx,
425 p_tbl->tcid);
426 return;
427 }
428 tAVDT_SCB_EVT avdt_scb_evt;
429 avdt_scb_evt.llcong = is_congested;
430 avdt_scb_event(p_scb, AVDT_SCB_TC_CONG_EVT, &avdt_scb_evt);
431 }
432
433 /*******************************************************************************
434 *
435 * Function avdt_ad_tc_data_ind
436 *
437 * Description This function is called by the L2CAP interface layer when
438 * incoming data is received from L2CAP. It looks up the CCB
439 * or SCB for the channel and routes the data accordingly.
440 *
441 *
442 * Returns Nothing.
443 *
444 ******************************************************************************/
avdt_ad_tc_data_ind(AvdtpTransportChannel * p_tbl,BT_HDR * p_buf)445 void avdt_ad_tc_data_ind(AvdtpTransportChannel* p_tbl, BT_HDR* p_buf) {
446 AvdtpCcb* p_ccb;
447 AvdtpScb* p_scb;
448
449 /* store type (media, recovery, reporting) */
450 p_buf->layer_specific = avdt_ad_tcid_to_type(p_tbl->tcid);
451
452 /* if signaling channel, handle control message */
453 if (p_tbl->tcid == 0) {
454 p_ccb = avdt_ccb_by_idx(p_tbl->ccb_idx);
455 avdt_msg_ind(p_ccb, p_buf);
456 return;
457 }
458 /* if media or other channel, send event to scb */
459 p_scb = avdtp_cb.ad.LookupAvdtpScb(*p_tbl);
460 if (p_scb == nullptr) {
461 log::error("Cannot find AvdtScb entry: ccb_idx:{} tcid:{}", p_tbl->ccb_idx,
462 p_tbl->tcid);
463 osi_free(p_buf);
464 log::error("buffer freed");
465 return;
466 }
467 avdt_scb_event(p_scb, AVDT_SCB_TC_DATA_EVT, (tAVDT_SCB_EVT*)&p_buf);
468 }
469
470 /*******************************************************************************
471 *
472 * Function avdt_ad_write_req
473 *
474 * Description This function is called by a CCB or SCB to send data to a
475 * transport channel. It looks up the LCID of the channel
476 * based on the type, CCB, and SCB (if present). Then it
477 * passes the data to L2CA_DataWrite().
478 *
479 *
480 * Returns AVDT_AD_SUCCESS, if data accepted
481 * AVDT_AD_CONGESTED, if data accepted and the channel is
482 * congested
483 * AVDT_AD_FAILED, if error
484 *
485 ******************************************************************************/
avdt_ad_write_req(uint8_t type,AvdtpCcb * p_ccb,AvdtpScb * p_scb,BT_HDR * p_buf)486 uint8_t avdt_ad_write_req(uint8_t type, AvdtpCcb* p_ccb, AvdtpScb* p_scb,
487 BT_HDR* p_buf) {
488 uint8_t tcid;
489
490 /* get tcid from type, scb */
491 tcid = avdt_ad_type_to_tcid(type, p_scb);
492
493 return L2CA_DataWrite(avdtp_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][tcid].lcid,
494 p_buf);
495 }
496
497 /*******************************************************************************
498 *
499 * Function avdt_ad_open_req
500 *
501 * Description This function is called by a CCB or SCB to open a transport
502 * channel. This function allocates and initializes a
503 * transport channel table entry. The channel can be opened
504 * in two roles: as an initiator or acceptor. When opened
505 * as an initiator the function will start an L2CAP connection.
506 * When opened as an acceptor the function simply configures
507 * the table entry to listen for an incoming channel.
508 *
509 *
510 * Returns Nothing.
511 *
512 ******************************************************************************/
avdt_ad_open_req(uint8_t type,AvdtpCcb * p_ccb,AvdtpScb * p_scb,uint8_t role)513 void avdt_ad_open_req(uint8_t type, AvdtpCcb* p_ccb, AvdtpScb* p_scb,
514 uint8_t role) {
515 AvdtpTransportChannel* p_tbl;
516 uint16_t lcid;
517
518 p_tbl = avdt_ad_tc_tbl_alloc(p_ccb);
519 if (p_tbl == NULL) {
520 log::error("avdt_ad_open_req: Cannot allocate p_tbl");
521 return;
522 }
523
524 p_tbl->tcid = avdt_ad_type_to_tcid(type, p_scb);
525 log::verbose("avdt_ad_open_req: type: {}, role: {}, tcid:{}", type, role,
526 p_tbl->tcid);
527
528 if (type == AVDT_CHAN_SIG) {
529 /* if signaling, get mtu from registration control block */
530 p_tbl->my_mtu = kAvdtpMtu;
531 } else {
532 /* otherwise get mtu from scb */
533 p_tbl->my_mtu = kAvdtpMtu;
534
535 /* also set scb_hdl in rt_tbl */
536 avdtp_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][p_tbl->tcid].scb_hdl =
537 avdt_scb_to_hdl(p_scb);
538 log::verbose("avdtp_cb.ad.rt_tbl[{}][{}].scb_hdl = {}",
539 avdt_ccb_to_idx(p_ccb), p_tbl->tcid, avdt_scb_to_hdl(p_scb));
540 }
541
542 /* if we're acceptor, we're done; just sit back and listen */
543 if (role == AVDT_ACP) {
544 p_tbl->state = AVDT_AD_ST_ACP;
545 }
546 /* else we're inititator, start the L2CAP connection */
547 else {
548 p_tbl->state = AVDT_AD_ST_CONN;
549
550 /* call l2cap connect req */
551 lcid = L2CA_ConnectReqWithSecurity(AVDT_PSM, p_ccb->peer_addr,
552 BTM_SEC_OUT_AUTHENTICATE);
553 if (lcid != 0) {
554 /* if connect req ok, store tcid in lcid table */
555 avdtp_cb.ad.lcid_tbl[lcid] = avdt_ad_tc_tbl_to_idx(p_tbl);
556 log::verbose("avdtp_cb.ad.lcid_tbl[{}] = {}", lcid,
557 avdt_ad_tc_tbl_to_idx(p_tbl));
558
559 avdtp_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][p_tbl->tcid].lcid = lcid;
560 log::verbose("avdtp_cb.ad.rt_tbl[{}][{}].lcid = 0x{:x}",
561 avdt_ccb_to_idx(p_ccb), p_tbl->tcid, lcid);
562 } else {
563 /* if connect req failed, call avdt_ad_tc_close_ind() */
564 avdt_ad_tc_close_ind(p_tbl);
565 }
566 }
567 }
568
569 /*******************************************************************************
570 *
571 * Function avdt_ad_close_req
572 *
573 * Description This function is called by a CCB or SCB to close a
574 * transport channel. The function looks up the LCID for the
575 * channel and calls L2CA_DisconnectReq().
576 *
577 *
578 * Returns Nothing.
579 *
580 ******************************************************************************/
avdt_ad_close_req(uint8_t type,AvdtpCcb * p_ccb,AvdtpScb * p_scb)581 void avdt_ad_close_req(uint8_t type, AvdtpCcb* p_ccb, AvdtpScb* p_scb) {
582 uint8_t tcid;
583 AvdtpTransportChannel* p_tbl;
584
585 p_tbl = avdt_ad_tc_tbl_by_type(type, p_ccb, p_scb);
586 log::verbose("avdt_ad_close_req state: {}", p_tbl->state);
587
588 switch (p_tbl->state) {
589 case AVDT_AD_ST_UNUSED:
590 /* probably for reporting */
591 break;
592 case AVDT_AD_ST_ACP:
593 /* if we're listening on this channel, send ourselves a close ind */
594 avdt_ad_tc_close_ind(p_tbl);
595 break;
596 default:
597 /* get tcid from type, scb */
598 tcid = avdt_ad_type_to_tcid(type, p_scb);
599
600 /* call l2cap disconnect req */
601 avdt_l2c_disconnect(
602 avdtp_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][tcid].lcid);
603 }
604 }
605