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