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 "data_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
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 /* Check the security */
206 rc = btm_sec_mx_access_request (bd_addr, AVDT_PSM,
207 FALSE, BTM_SEC_PROTO_AVDT,
208 AVDT_CHAN_SIG,
209 &avdt_sec_check_complete_term, NULL);
210 if(rc == BTM_CMD_STARTED)
211 {
212 L2CA_ConnectRsp (p_ccb->peer_addr, p_tbl->id, lcid, L2CAP_CONN_PENDING, L2CAP_CONN_OK);
213 }
214 return;
215 }
216 }
217 /* deal with simultaneous control channel connect case */
218 else if ((p_tbl = avdt_ad_tc_tbl_by_st(AVDT_CHAN_SIG, p_ccb, AVDT_AD_ST_CONN)) != NULL)
219 {
220 /* reject their connection */
221 result = L2CAP_CONN_NO_RESOURCES;
222 }
223 /* this must be a traffic channel; are we accepting a traffic channel
224 ** for this ccb?
225 */
226 else if ((p_tbl = avdt_ad_tc_tbl_by_st(AVDT_CHAN_MEDIA, p_ccb, AVDT_AD_ST_ACP)) != NULL)
227 {
228 /* yes; proceed with connection */
229 result = L2CAP_CONN_OK;
230 }
231 #if AVDT_REPORTING == TRUE
232 /* this must be a reporting channel; are we accepting a reporting channel
233 ** for this ccb?
234 */
235 else if ((p_tbl = avdt_ad_tc_tbl_by_st(AVDT_CHAN_REPORT, p_ccb, AVDT_AD_ST_ACP)) != NULL)
236 {
237 /* yes; proceed with connection */
238 result = L2CAP_CONN_OK;
239 }
240 #endif
241 /* else we're not listening for traffic channel; reject */
242 else
243 {
244 result = L2CAP_CONN_NO_PSM;
245 }
246
247 /* Send L2CAP connect rsp */
248 L2CA_ConnectRsp(bd_addr, id, lcid, result, 0);
249
250 /* if result ok, proceed with connection */
251 if (result == L2CAP_CONN_OK)
252 {
253 /* store idx in LCID table, store LCID in routing table */
254 avdt_cb.ad.lcid_tbl[lcid - L2CAP_BASE_APPL_CID] = avdt_ad_tc_tbl_to_idx(p_tbl);
255 avdt_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][p_tbl->tcid].lcid = lcid;
256
257 /* transition to configuration state */
258 p_tbl->state = AVDT_AD_ST_CFG;
259
260 /* Send L2CAP config req */
261 memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
262 cfg.mtu_present = TRUE;
263 cfg.mtu = p_tbl->my_mtu;
264 cfg.flush_to_present = TRUE;
265 cfg.flush_to = p_tbl->my_flush_to;
266 L2CA_ConfigReq(lcid, &cfg);
267 }
268 }
269
270 /*******************************************************************************
271 **
272 ** Function avdt_l2c_connect_cfm_cback
273 **
274 ** Description This is the L2CAP connect confirm callback function.
275 **
276 **
277 ** Returns void
278 **
279 *******************************************************************************/
avdt_l2c_connect_cfm_cback(UINT16 lcid,UINT16 result)280 void avdt_l2c_connect_cfm_cback(UINT16 lcid, UINT16 result)
281 {
282 tAVDT_TC_TBL *p_tbl;
283 tL2CAP_CFG_INFO cfg;
284 tAVDT_CCB *p_ccb;
285
286 AVDT_TRACE_DEBUG("avdt_l2c_connect_cfm_cback lcid: %d, result: %d",
287 lcid, result);
288 /* look up info for this channel */
289 if ((p_tbl = avdt_ad_tc_tbl_by_lcid(lcid)) != NULL)
290 {
291 /* if in correct state */
292 if (p_tbl->state == AVDT_AD_ST_CONN)
293 {
294 /* if result successful */
295 if (result == L2CAP_CONN_OK)
296 {
297 if(p_tbl->tcid != AVDT_CHAN_SIG)
298 {
299 /* set channel state */
300 p_tbl->state = AVDT_AD_ST_CFG;
301
302 /* Send L2CAP config req */
303 memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
304 cfg.mtu_present = TRUE;
305 cfg.mtu = p_tbl->my_mtu;
306 cfg.flush_to_present = TRUE;
307 cfg.flush_to = p_tbl->my_flush_to;
308 L2CA_ConfigReq(lcid, &cfg);
309 }
310 else
311 {
312 p_ccb = avdt_ccb_by_idx(p_tbl->ccb_idx);
313 if(p_ccb == NULL)
314 {
315 result = L2CAP_CONN_NO_RESOURCES;
316 }
317 else
318 {
319 /* set channel state */
320 p_tbl->state = AVDT_AD_ST_SEC_INT;
321 p_tbl->lcid = lcid;
322 p_tbl->cfg_flags = AVDT_L2C_CFG_CONN_INT;
323
324 /* Check the security */
325 btm_sec_mx_access_request (p_ccb->peer_addr, AVDT_PSM,
326 TRUE, BTM_SEC_PROTO_AVDT,
327 AVDT_CHAN_SIG,
328 &avdt_sec_check_complete_orig, NULL);
329 }
330 }
331 }
332
333 /* failure; notify adaption that channel closed */
334 if (result != L2CAP_CONN_OK)
335 {
336 avdt_ad_tc_close_ind(p_tbl, result);
337 }
338 }
339 }
340 }
341
342 /*******************************************************************************
343 **
344 ** Function avdt_l2c_config_cfm_cback
345 **
346 ** Description This is the L2CAP config confirm callback function.
347 **
348 **
349 ** Returns void
350 **
351 *******************************************************************************/
avdt_l2c_config_cfm_cback(UINT16 lcid,tL2CAP_CFG_INFO * p_cfg)352 void avdt_l2c_config_cfm_cback(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg)
353 {
354 tAVDT_TC_TBL *p_tbl;
355
356 /* look up info for this channel */
357 if ((p_tbl = avdt_ad_tc_tbl_by_lcid(lcid)) != NULL)
358 {
359 /* if in correct state */
360 if (p_tbl->state == AVDT_AD_ST_CFG)
361 {
362 /* if result successful */
363 if (p_cfg->result == L2CAP_CONN_OK)
364 {
365 /* update cfg_flags */
366 p_tbl->cfg_flags |= AVDT_L2C_CFG_CFM_DONE;
367
368 /* if configuration complete */
369 if (p_tbl->cfg_flags & AVDT_L2C_CFG_IND_DONE)
370 {
371 avdt_ad_tc_open_ind(p_tbl);
372 }
373 }
374 /* else failure */
375 else
376 {
377 /* Send L2CAP disconnect req */
378 L2CA_DisconnectReq(lcid);
379 }
380 }
381 }
382 }
383
384 /*******************************************************************************
385 **
386 ** Function avdt_l2c_config_ind_cback
387 **
388 ** Description This is the L2CAP config indication callback function.
389 **
390 **
391 ** Returns void
392 **
393 *******************************************************************************/
avdt_l2c_config_ind_cback(UINT16 lcid,tL2CAP_CFG_INFO * p_cfg)394 void avdt_l2c_config_ind_cback(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg)
395 {
396 tAVDT_TC_TBL *p_tbl;
397
398 /* look up info for this channel */
399 if ((p_tbl = avdt_ad_tc_tbl_by_lcid(lcid)) != NULL)
400 {
401 /* store the mtu in tbl */
402 if (p_cfg->mtu_present)
403 {
404 p_tbl->peer_mtu = p_cfg->mtu;
405 }
406 else
407 {
408 p_tbl->peer_mtu = L2CAP_DEFAULT_MTU;
409 }
410 AVDT_TRACE_DEBUG("peer_mtu: %d, lcid: x%x",p_tbl->peer_mtu, lcid);
411
412 /* send L2CAP configure response */
413 memset(p_cfg, 0, sizeof(tL2CAP_CFG_INFO));
414 p_cfg->result = L2CAP_CFG_OK;
415 L2CA_ConfigRsp(lcid, p_cfg);
416
417 /* if first config ind */
418 if ((p_tbl->cfg_flags & AVDT_L2C_CFG_IND_DONE) == 0)
419 {
420 /* update cfg_flags */
421 p_tbl->cfg_flags |= AVDT_L2C_CFG_IND_DONE;
422
423 /* if configuration complete */
424 if (p_tbl->cfg_flags & AVDT_L2C_CFG_CFM_DONE)
425 {
426 avdt_ad_tc_open_ind(p_tbl);
427 }
428 }
429 }
430 }
431
432 /*******************************************************************************
433 **
434 ** Function avdt_l2c_disconnect_ind_cback
435 **
436 ** Description This is the L2CAP disconnect indication callback function.
437 **
438 **
439 ** Returns void
440 **
441 *******************************************************************************/
avdt_l2c_disconnect_ind_cback(UINT16 lcid,BOOLEAN ack_needed)442 void avdt_l2c_disconnect_ind_cback(UINT16 lcid, BOOLEAN ack_needed)
443 {
444 tAVDT_TC_TBL *p_tbl;
445
446 AVDT_TRACE_DEBUG("avdt_l2c_disconnect_ind_cback lcid: %d, ack_needed: %d",
447 lcid, ack_needed);
448 /* look up info for this channel */
449 if ((p_tbl = avdt_ad_tc_tbl_by_lcid(lcid)) != NULL)
450 {
451 if (ack_needed)
452 {
453 /* send L2CAP disconnect response */
454 L2CA_DisconnectRsp(lcid);
455 }
456
457 avdt_ad_tc_close_ind(p_tbl, 0);
458 }
459 }
460
461 /*******************************************************************************
462 **
463 ** Function avdt_l2c_disconnect_cfm_cback
464 **
465 ** Description This is the L2CAP disconnect confirm callback function.
466 **
467 **
468 ** Returns void
469 **
470 *******************************************************************************/
avdt_l2c_disconnect_cfm_cback(UINT16 lcid,UINT16 result)471 void avdt_l2c_disconnect_cfm_cback(UINT16 lcid, UINT16 result)
472 {
473 tAVDT_TC_TBL *p_tbl;
474
475 AVDT_TRACE_DEBUG("avdt_l2c_disconnect_cfm_cback lcid: %d, result: %d",
476 lcid, result);
477 /* look up info for this channel */
478 if ((p_tbl = avdt_ad_tc_tbl_by_lcid(lcid)) != NULL)
479 {
480 avdt_ad_tc_close_ind(p_tbl, result);
481 }
482 }
483
484 /*******************************************************************************
485 **
486 ** Function avdt_l2c_congestion_ind_cback
487 **
488 ** Description This is the L2CAP congestion indication callback function.
489 **
490 **
491 ** Returns void
492 **
493 *******************************************************************************/
avdt_l2c_congestion_ind_cback(UINT16 lcid,BOOLEAN is_congested)494 void avdt_l2c_congestion_ind_cback(UINT16 lcid, BOOLEAN is_congested)
495 {
496 tAVDT_TC_TBL *p_tbl;
497
498 /* look up info for this channel */
499 if ((p_tbl = avdt_ad_tc_tbl_by_lcid(lcid)) != NULL)
500 {
501 avdt_ad_tc_cong_ind(p_tbl, is_congested);
502 }
503 }
504
505 /*******************************************************************************
506 **
507 ** Function avdt_l2c_data_ind_cback
508 **
509 ** Description This is the L2CAP data indication callback function.
510 **
511 **
512 ** Returns void
513 **
514 *******************************************************************************/
avdt_l2c_data_ind_cback(UINT16 lcid,BT_HDR * p_buf)515 void avdt_l2c_data_ind_cback(UINT16 lcid, BT_HDR *p_buf)
516 {
517 tAVDT_TC_TBL *p_tbl;
518
519 /* look up info for this channel */
520 if ((p_tbl = avdt_ad_tc_tbl_by_lcid(lcid)) != NULL)
521 {
522 avdt_ad_tc_data_ind(p_tbl, p_buf);
523 }
524 else /* prevent buffer leak */
525 GKI_freebuf(p_buf);
526 }
527
528