1 /******************************************************************************
2 *
3 * Copyright (C) 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 AVDTP adaption layer module interfaces to L2CAP
22 *
23 ******************************************************************************/
24
25 #include <string.h>
26 #include "stack/bt_types.h"
27 #include "common/bt_target.h"
28 #include "common/bt_defs.h"
29 #include "stack/avdt_api.h"
30 #include "stack/avdtc_api.h"
31 #include "avdt_int.h"
32 #include "stack/l2c_api.h"
33 #include "stack/l2cdefs.h"
34 #include "stack/btm_api.h"
35 #include "btm_int.h"
36 #include "osi/allocator.h"
37
38 #if (defined(AVDT_INCLUDED) && AVDT_INCLUDED == TRUE)
39
40 /* callback function declarations */
41 void avdt_l2c_connect_ind_cback(BD_ADDR bd_addr, UINT16 lcid, UINT16 psm, UINT8 id);
42 void avdt_l2c_connect_cfm_cback(UINT16 lcid, UINT16 result);
43 void avdt_l2c_config_cfm_cback(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg);
44 void avdt_l2c_config_ind_cback(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg);
45 void avdt_l2c_disconnect_ind_cback(UINT16 lcid, BOOLEAN ack_needed);
46 void avdt_l2c_disconnect_cfm_cback(UINT16 lcid, UINT16 result);
47 void avdt_l2c_congestion_ind_cback(UINT16 lcid, BOOLEAN is_congested);
48 void avdt_l2c_data_ind_cback(UINT16 lcid, BT_HDR *p_buf);
49
50 /* L2CAP callback function structure */
51 const tL2CAP_APPL_INFO avdt_l2c_appl = {
52 avdt_l2c_connect_ind_cback,
53 avdt_l2c_connect_cfm_cback,
54 NULL,
55 avdt_l2c_config_ind_cback,
56 avdt_l2c_config_cfm_cback,
57 avdt_l2c_disconnect_ind_cback,
58 avdt_l2c_disconnect_cfm_cback,
59 NULL,
60 avdt_l2c_data_ind_cback,
61 avdt_l2c_congestion_ind_cback,
62 NULL /* tL2CA_TX_COMPLETE_CB */
63 };
64
65 /*******************************************************************************
66 **
67 ** Function avdt_sec_check_complete_term
68 **
69 ** Description The function called when Security Manager finishes
70 ** verification of the service side connection
71 **
72 ** Returns void
73 **
74 *******************************************************************************/
avdt_sec_check_complete_term(BD_ADDR bd_addr,tBT_TRANSPORT transport,void * p_ref_data,UINT8 res)75 static void avdt_sec_check_complete_term (BD_ADDR bd_addr, tBT_TRANSPORT transport,
76 void *p_ref_data, UINT8 res)
77 {
78 tAVDT_CCB *p_ccb = NULL;
79 tL2CAP_CFG_INFO cfg;
80 tAVDT_TC_TBL *p_tbl;
81 UNUSED(p_ref_data);
82
83 AVDT_TRACE_DEBUG("avdt_sec_check_complete_term res: %d\n", res);
84 if (!bd_addr) {
85 AVDT_TRACE_WARNING("avdt_sec_check_complete_term: NULL BD_ADDR");
86 return;
87
88 }
89 p_ccb = avdt_ccb_by_bd(bd_addr);
90
91 p_tbl = avdt_ad_tc_tbl_by_st(AVDT_CHAN_SIG, p_ccb, AVDT_AD_ST_SEC_ACP);
92 if (p_tbl == NULL) {
93 return;
94 }
95
96 if (res == BTM_SUCCESS) {
97 /* Send response to the L2CAP layer. */
98 L2CA_ConnectRsp (bd_addr, p_tbl->id, p_tbl->lcid, L2CAP_CONN_OK, L2CAP_CONN_OK);
99
100 /* store idx in LCID table, store LCID in routing table */
101 avdt_cb.ad.lcid_tbl[p_tbl->lcid - L2CAP_BASE_APPL_CID] = avdt_ad_tc_tbl_to_idx(p_tbl);
102 avdt_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][p_tbl->tcid].lcid = p_tbl->lcid;
103
104 /* transition to configuration state */
105 p_tbl->state = AVDT_AD_ST_CFG;
106
107 /* Send L2CAP config req */
108 memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
109 cfg.mtu_present = TRUE;
110 cfg.mtu = p_tbl->my_mtu;
111 cfg.flush_to_present = TRUE;
112 cfg.flush_to = p_tbl->my_flush_to;
113 L2CA_ConfigReq(p_tbl->lcid, &cfg);
114 } else {
115 L2CA_ConnectRsp (bd_addr, p_tbl->id, p_tbl->lcid, L2CAP_CONN_SECURITY_BLOCK, L2CAP_CONN_OK);
116 avdt_ad_tc_close_ind(p_tbl, L2CAP_CONN_SECURITY_BLOCK);
117 }
118 }
119
120 /*******************************************************************************
121 **
122 ** Function avdt_sec_check_complete_orig
123 **
124 ** Description The function called when Security Manager finishes
125 ** verification of the service side connection
126 **
127 ** Returns void
128 **
129 *******************************************************************************/
avdt_sec_check_complete_orig(BD_ADDR bd_addr,tBT_TRANSPORT transport,void * p_ref_data,UINT8 res)130 static void avdt_sec_check_complete_orig (BD_ADDR bd_addr, tBT_TRANSPORT transport,
131 void *p_ref_data, UINT8 res)
132 {
133 tAVDT_CCB *p_ccb = NULL;
134 tL2CAP_CFG_INFO cfg;
135 tAVDT_TC_TBL *p_tbl;
136 UNUSED(p_ref_data);
137
138 AVDT_TRACE_DEBUG("avdt_sec_check_complete_orig res: %d\n", res);
139 if (bd_addr) {
140 p_ccb = avdt_ccb_by_bd(bd_addr);
141 }
142 p_tbl = avdt_ad_tc_tbl_by_st(AVDT_CHAN_SIG, p_ccb, AVDT_AD_ST_SEC_INT);
143 if (p_tbl == NULL) {
144 return;
145 }
146
147 if ( res == BTM_SUCCESS ) {
148 /* set channel state */
149 p_tbl->state = AVDT_AD_ST_CFG;
150
151 /* Send L2CAP config req */
152 memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
153 cfg.mtu_present = TRUE;
154 cfg.mtu = p_tbl->my_mtu;
155 cfg.flush_to_present = TRUE;
156 cfg.flush_to = p_tbl->my_flush_to;
157 L2CA_ConfigReq(p_tbl->lcid, &cfg);
158 } else {
159 L2CA_DisconnectReq (p_tbl->lcid);
160 avdt_ad_tc_close_ind(p_tbl, L2CAP_CONN_SECURITY_BLOCK);
161 }
162 }
163 /*******************************************************************************
164 **
165 ** Function avdt_l2c_connect_ind_cback
166 **
167 ** Description This is the L2CAP connect indication callback function.
168 **
169 **
170 ** Returns void
171 **
172 *******************************************************************************/
avdt_l2c_connect_ind_cback(BD_ADDR bd_addr,UINT16 lcid,UINT16 psm,UINT8 id)173 void avdt_l2c_connect_ind_cback(BD_ADDR bd_addr, UINT16 lcid, UINT16 psm, UINT8 id)
174 {
175 tAVDT_CCB *p_ccb;
176 tAVDT_TC_TBL *p_tbl = NULL;
177 UINT16 result;
178 tL2CAP_CFG_INFO cfg;
179 tBTM_STATUS rc;
180 UNUSED(psm);
181
182 /* do we already have a control channel for this peer? */
183 if ((p_ccb = avdt_ccb_by_bd(bd_addr)) == NULL) {
184 /* no, allocate ccb */
185 if ((p_ccb = avdt_ccb_alloc(bd_addr)) == NULL) {
186 /* no ccb available, reject L2CAP connection */
187 result = L2CAP_CONN_NO_RESOURCES;
188 } else {
189 /* allocate and set up entry; first channel is always signaling */
190 p_tbl = avdt_ad_tc_tbl_alloc(p_ccb);
191 p_tbl->my_mtu = avdt_cb.rcb.ctrl_mtu;
192 p_tbl->my_flush_to = L2CAP_DEFAULT_FLUSH_TO;
193 p_tbl->tcid = AVDT_CHAN_SIG;
194 p_tbl->lcid = lcid;
195 p_tbl->id = id;
196 p_tbl->state = AVDT_AD_ST_SEC_ACP;
197 p_tbl->cfg_flags = AVDT_L2C_CFG_CONN_ACP;
198
199 /* Check the security */
200 rc = btm_sec_mx_access_request (bd_addr, AVDT_PSM,
201 FALSE, BTM_SEC_PROTO_AVDT,
202 AVDT_CHAN_SIG,
203 &avdt_sec_check_complete_term, NULL);
204 if (rc == BTM_CMD_STARTED) {
205 L2CA_ConnectRsp (p_ccb->peer_addr, p_tbl->id, lcid, L2CAP_CONN_PENDING, L2CAP_CONN_OK);
206 }
207 return;
208 }
209 }
210 /* deal with simultaneous control channel connect case */
211 else if ((p_tbl = avdt_ad_tc_tbl_by_st(AVDT_CHAN_SIG, p_ccb, AVDT_AD_ST_CONN)) != NULL) {
212 /* reject their connection */
213 result = L2CAP_CONN_NO_RESOURCES;
214 }
215 /* this must be a traffic channel; are we accepting a traffic channel
216 ** for this ccb?
217 */
218 else if ((p_tbl = avdt_ad_tc_tbl_by_st(AVDT_CHAN_MEDIA, p_ccb, AVDT_AD_ST_ACP)) != NULL) {
219 /* yes; proceed with connection */
220 result = L2CAP_CONN_OK;
221 }
222 #if AVDT_REPORTING == TRUE
223 /* this must be a reporting channel; are we accepting a reporting channel
224 ** for this ccb?
225 */
226 else if ((p_tbl = avdt_ad_tc_tbl_by_st(AVDT_CHAN_REPORT, p_ccb, AVDT_AD_ST_ACP)) != NULL) {
227 /* yes; proceed with connection */
228 result = L2CAP_CONN_OK;
229 }
230 #endif
231 /* else we're not listening for traffic channel; reject */
232 else {
233 result = L2CAP_CONN_NO_PSM;
234 }
235
236 /* Send L2CAP connect rsp */
237 L2CA_ConnectRsp(bd_addr, id, lcid, result, 0);
238
239 /* if result ok, proceed with connection */
240 if (result == L2CAP_CONN_OK) {
241 /* store idx in LCID table, store LCID in routing table */
242 avdt_cb.ad.lcid_tbl[lcid - L2CAP_BASE_APPL_CID] = avdt_ad_tc_tbl_to_idx(p_tbl);
243 avdt_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][p_tbl->tcid].lcid = lcid;
244
245 /* transition to configuration state */
246 p_tbl->state = AVDT_AD_ST_CFG;
247
248 /* Send L2CAP config req */
249 memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
250 cfg.mtu_present = TRUE;
251 cfg.mtu = p_tbl->my_mtu;
252 cfg.flush_to_present = TRUE;
253 cfg.flush_to = p_tbl->my_flush_to;
254 L2CA_ConfigReq(lcid, &cfg);
255 }
256 }
257
258 /*******************************************************************************
259 **
260 ** Function avdt_l2c_connect_cfm_cback
261 **
262 ** Description This is the L2CAP connect confirm callback function.
263 **
264 **
265 ** Returns void
266 **
267 *******************************************************************************/
avdt_l2c_connect_cfm_cback(UINT16 lcid,UINT16 result)268 void avdt_l2c_connect_cfm_cback(UINT16 lcid, UINT16 result)
269 {
270 tAVDT_TC_TBL *p_tbl;
271 tL2CAP_CFG_INFO cfg;
272 tAVDT_CCB *p_ccb;
273
274 AVDT_TRACE_DEBUG("avdt_l2c_connect_cfm_cback lcid: %d, result: %d\n",
275 lcid, result);
276 /* look up info for this channel */
277 if ((p_tbl = avdt_ad_tc_tbl_by_lcid(lcid)) != NULL) {
278 /* if in correct state */
279 if (p_tbl->state == AVDT_AD_ST_CONN) {
280 /* if result successful */
281 if (result == L2CAP_CONN_OK) {
282 if (p_tbl->tcid != AVDT_CHAN_SIG) {
283 /* set channel state */
284 p_tbl->state = AVDT_AD_ST_CFG;
285
286 /* Send L2CAP config req */
287 memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
288 cfg.mtu_present = TRUE;
289 cfg.mtu = p_tbl->my_mtu;
290 cfg.flush_to_present = TRUE;
291 cfg.flush_to = p_tbl->my_flush_to;
292 L2CA_ConfigReq(lcid, &cfg);
293 } else {
294 p_ccb = avdt_ccb_by_idx(p_tbl->ccb_idx);
295 if (p_ccb == NULL) {
296 result = L2CAP_CONN_NO_RESOURCES;
297 } else {
298 /* set channel state */
299 p_tbl->state = AVDT_AD_ST_SEC_INT;
300 p_tbl->lcid = lcid;
301 p_tbl->cfg_flags = AVDT_L2C_CFG_CONN_INT;
302
303 /* Check the security */
304 btm_sec_mx_access_request (p_ccb->peer_addr, AVDT_PSM,
305 TRUE, BTM_SEC_PROTO_AVDT,
306 AVDT_CHAN_SIG,
307 &avdt_sec_check_complete_orig, NULL);
308 }
309 }
310 }
311
312 /* failure; notify adaption that channel closed */
313 if (result != L2CAP_CONN_OK) {
314 avdt_ad_tc_close_ind(p_tbl, result);
315 }
316 }
317 }
318 }
319
320 /*******************************************************************************
321 **
322 ** Function avdt_l2c_config_cfm_cback
323 **
324 ** Description This is the L2CAP config confirm callback function.
325 **
326 **
327 ** Returns void
328 **
329 *******************************************************************************/
avdt_l2c_config_cfm_cback(UINT16 lcid,tL2CAP_CFG_INFO * p_cfg)330 void avdt_l2c_config_cfm_cback(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg)
331 {
332 tAVDT_TC_TBL *p_tbl;
333
334 /* look up info for this channel */
335 if ((p_tbl = avdt_ad_tc_tbl_by_lcid(lcid)) != NULL) {
336 p_tbl->lcid = lcid;
337
338 /* if in correct state */
339 if (p_tbl->state == AVDT_AD_ST_CFG) {
340 /* if result successful */
341 if (p_cfg->result == L2CAP_CONN_OK) {
342 /* update cfg_flags */
343 p_tbl->cfg_flags |= AVDT_L2C_CFG_CFM_DONE;
344
345 /* if configuration complete */
346 if (p_tbl->cfg_flags & AVDT_L2C_CFG_IND_DONE) {
347 avdt_ad_tc_open_ind(p_tbl);
348 }
349 }
350 /* else failure */
351 else {
352 /* Send L2CAP disconnect req */
353 L2CA_DisconnectReq(lcid);
354 }
355 }
356 }
357 }
358
359 /*******************************************************************************
360 **
361 ** Function avdt_l2c_config_ind_cback
362 **
363 ** Description This is the L2CAP config indication callback function.
364 **
365 **
366 ** Returns void
367 **
368 *******************************************************************************/
avdt_l2c_config_ind_cback(UINT16 lcid,tL2CAP_CFG_INFO * p_cfg)369 void avdt_l2c_config_ind_cback(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg)
370 {
371 tAVDT_TC_TBL *p_tbl;
372
373 /* look up info for this channel */
374 if ((p_tbl = avdt_ad_tc_tbl_by_lcid(lcid)) != NULL) {
375 /* store the mtu in tbl */
376 if (p_cfg->mtu_present) {
377 p_tbl->peer_mtu = p_cfg->mtu;
378 } else {
379 p_tbl->peer_mtu = L2CAP_DEFAULT_MTU;
380 }
381 AVDT_TRACE_DEBUG("peer_mtu: %d, lcid: x%x\n", p_tbl->peer_mtu, lcid);
382
383 /* send L2CAP configure response */
384 memset(p_cfg, 0, sizeof(tL2CAP_CFG_INFO));
385 p_cfg->result = L2CAP_CFG_OK;
386 L2CA_ConfigRsp(lcid, p_cfg);
387
388 /* if first config ind */
389 if ((p_tbl->cfg_flags & AVDT_L2C_CFG_IND_DONE) == 0) {
390 /* update cfg_flags */
391 p_tbl->cfg_flags |= AVDT_L2C_CFG_IND_DONE;
392
393 /* if configuration complete */
394 if (p_tbl->cfg_flags & AVDT_L2C_CFG_CFM_DONE) {
395 avdt_ad_tc_open_ind(p_tbl);
396 }
397 }
398 }
399 }
400
401 /*******************************************************************************
402 **
403 ** Function avdt_l2c_disconnect_ind_cback
404 **
405 ** Description This is the L2CAP disconnect indication callback function.
406 **
407 **
408 ** Returns void
409 **
410 *******************************************************************************/
avdt_l2c_disconnect_ind_cback(UINT16 lcid,BOOLEAN ack_needed)411 void avdt_l2c_disconnect_ind_cback(UINT16 lcid, BOOLEAN ack_needed)
412 {
413 tAVDT_TC_TBL *p_tbl;
414 UINT16 disc_rsn = AVDT_DISC_RSN_NORMAL;
415 tAVDT_CCB *p_ccb;
416 AVDT_TRACE_DEBUG("avdt_l2c_disconnect_ind_cback lcid: %d, ack_needed: %d\n",
417 lcid, ack_needed);
418 /* look up info for this channel */
419 if ((p_tbl = avdt_ad_tc_tbl_by_lcid(lcid)) != NULL) {
420 if (ack_needed) {
421 /* send L2CAP disconnect response */
422 L2CA_DisconnectRsp(lcid);
423 } else {
424 if ((p_ccb = avdt_ccb_by_idx(p_tbl->ccb_idx)) != NULL) {
425 UINT16 rsn = L2CA_GetDisconnectReason(p_ccb->peer_addr, BT_TRANSPORT_BR_EDR);
426 if (rsn != 0 && rsn != HCI_ERR_PEER_USER) {
427 disc_rsn = AVDT_DISC_RSN_ABNORMAL;
428 AVDT_TRACE_EVENT("avdt link disc rsn 0x%x", rsn);
429 }
430 }
431 }
432
433 avdt_ad_tc_close_ind(p_tbl, disc_rsn);
434 }
435 }
436
437 /*******************************************************************************
438 **
439 ** Function avdt_l2c_disconnect_cfm_cback
440 **
441 ** Description This is the L2CAP disconnect confirm callback function.
442 **
443 **
444 ** Returns void
445 **
446 *******************************************************************************/
avdt_l2c_disconnect_cfm_cback(UINT16 lcid,UINT16 result)447 void avdt_l2c_disconnect_cfm_cback(UINT16 lcid, UINT16 result)
448 {
449 tAVDT_TC_TBL *p_tbl;
450
451 AVDT_TRACE_DEBUG("avdt_l2c_disconnect_cfm_cback lcid: %d, result: %d\n",
452 lcid, result);
453 /* look up info for this channel */
454 if ((p_tbl = avdt_ad_tc_tbl_by_lcid(lcid)) != NULL) {
455 avdt_ad_tc_close_ind(p_tbl, result);
456 }
457 }
458
459 /*******************************************************************************
460 **
461 ** Function avdt_l2c_congestion_ind_cback
462 **
463 ** Description This is the L2CAP congestion indication callback function.
464 **
465 **
466 ** Returns void
467 **
468 *******************************************************************************/
avdt_l2c_congestion_ind_cback(UINT16 lcid,BOOLEAN is_congested)469 void avdt_l2c_congestion_ind_cback(UINT16 lcid, BOOLEAN is_congested)
470 {
471 tAVDT_TC_TBL *p_tbl;
472
473 /* look up info for this channel */
474 if ((p_tbl = avdt_ad_tc_tbl_by_lcid(lcid)) != NULL) {
475 avdt_ad_tc_cong_ind(p_tbl, is_congested);
476 }
477 }
478
479 /*******************************************************************************
480 **
481 ** Function avdt_l2c_data_ind_cback
482 **
483 ** Description This is the L2CAP data indication callback function.
484 **
485 **
486 ** Returns void
487 **
488 *******************************************************************************/
avdt_l2c_data_ind_cback(UINT16 lcid,BT_HDR * p_buf)489 void avdt_l2c_data_ind_cback(UINT16 lcid, BT_HDR *p_buf)
490 {
491 tAVDT_TC_TBL *p_tbl;
492
493 /* look up info for this channel */
494 if ((p_tbl = avdt_ad_tc_tbl_by_lcid(lcid)) != NULL) {
495 avdt_ad_tc_data_ind(p_tbl, p_buf);
496 } else { /* prevent buffer leak */
497 osi_free(p_buf);
498 }
499 }
500
501 #endif /* #if (defined(AVDT_INCLUDED) && AVDT_INCLUDED == TRUE) */
502