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