• 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 "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