• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /******************************************************************************
2  *
3  *  Copyright (C) 2003-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 AVCTP module interfaces to L2CAP
22  *
23  ******************************************************************************/
24 
25 #include <string.h>
26 #include "data_types.h"
27 #include "bt_target.h"
28 #include "avct_api.h"
29 #include "avct_int.h"
30 #include "l2c_api.h"
31 #include "l2cdefs.h"
32 
33 /* Configuration flags. */
34 #define AVCT_L2C_CFG_IND_DONE   (1<<0)
35 #define AVCT_L2C_CFG_CFM_DONE   (1<<1)
36 
37 /* callback function declarations */
38 void avct_l2c_connect_ind_cback(BD_ADDR bd_addr, UINT16 lcid, UINT16 psm, UINT8 id);
39 void avct_l2c_connect_cfm_cback(UINT16 lcid, UINT16 result);
40 void avct_l2c_config_cfm_cback(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg);
41 void avct_l2c_config_ind_cback(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg);
42 void avct_l2c_disconnect_ind_cback(UINT16 lcid, BOOLEAN ack_needed);
43 void avct_l2c_disconnect_cfm_cback(UINT16 lcid, UINT16 result);
44 void avct_l2c_congestion_ind_cback(UINT16 lcid, BOOLEAN is_congested);
45 void avct_l2c_data_ind_cback(UINT16 lcid, BT_HDR *p_buf);
46 
47 /* L2CAP callback function structure */
48 const tL2CAP_APPL_INFO avct_l2c_appl = {
49     avct_l2c_connect_ind_cback,
50     avct_l2c_connect_cfm_cback,
51     NULL,
52     avct_l2c_config_ind_cback,
53     avct_l2c_config_cfm_cback,
54     avct_l2c_disconnect_ind_cback,
55     avct_l2c_disconnect_cfm_cback,
56     NULL,
57     avct_l2c_data_ind_cback,
58     avct_l2c_congestion_ind_cback,
59     NULL                                /* tL2CA_TX_COMPLETE_CB */
60 };
61 
62 /*******************************************************************************
63 **
64 ** Function         avct_l2c_is_passive
65 **
66 ** Description      check is the CCB associated with the given LCB was created
67 **                  as passive
68 **
69 ** Returns          TRUE, if the given LCB is created as AVCT_PASSIVE
70 **
71 *******************************************************************************/
avct_l2c_is_passive(tAVCT_LCB * p_lcb)72 static BOOLEAN avct_l2c_is_passive (tAVCT_LCB *p_lcb)
73 {
74     BOOLEAN     is_passive = FALSE;
75     tAVCT_CCB   *p_ccb = &avct_cb.ccb[0];
76     int         i;
77 
78     for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++)
79     {
80         if (p_ccb->allocated && (p_ccb->p_lcb == p_lcb))
81         {
82             AVCT_TRACE_DEBUG1("avct_l2c_is_ct control:x%x", p_ccb->cc.control);
83             if (p_ccb->cc.control & AVCT_PASSIVE)
84             {
85                 is_passive = TRUE;
86                 break;
87             }
88         }
89     }
90     return is_passive;
91 }
92 
93 /*******************************************************************************
94 **
95 ** Function         avct_l2c_connect_ind_cback
96 **
97 ** Description      This is the L2CAP connect indication callback function.
98 **
99 **
100 ** Returns          void
101 **
102 *******************************************************************************/
avct_l2c_connect_ind_cback(BD_ADDR bd_addr,UINT16 lcid,UINT16 psm,UINT8 id)103 void avct_l2c_connect_ind_cback(BD_ADDR bd_addr, UINT16 lcid, UINT16 psm, UINT8 id)
104 {
105     tAVCT_LCB       *p_lcb;
106     UINT16          result = L2CAP_CONN_OK;
107     tL2CAP_CFG_INFO cfg;
108 
109     /* do we already have a channel for this peer? */
110     if ((p_lcb = avct_lcb_by_bd(bd_addr)) == NULL)
111     {
112         /* no, allocate lcb */
113         if ((p_lcb = avct_lcb_alloc(bd_addr)) == NULL)
114         {
115             /* no ccb available, reject L2CAP connection */
116             result = L2CAP_CONN_NO_RESOURCES;
117         }
118     }
119     /* else we already have a channel for this peer */
120     else
121     {
122         if (!avct_l2c_is_passive (p_lcb) || (p_lcb->ch_state == AVCT_CH_OPEN))
123         {
124             /* this LCB included CT role - reject */
125             result = L2CAP_CONN_NO_RESOURCES;
126         }
127         else
128         {
129             /* TG role only - accept the connection from CT. move the channel ID to the conflict list */
130             p_lcb->conflict_lcid = p_lcb->ch_lcid;
131             AVCT_TRACE_DEBUG1("avct_l2c_connect_ind_cback conflict_lcid:0x%x", p_lcb->conflict_lcid);
132         }
133     }
134 
135     if(p_lcb)
136     {
137         AVCT_TRACE_DEBUG3("avct_l2c_connect_ind_cback: 0x%x, res: %d, ch_state: %d",
138             lcid, result, p_lcb->ch_state);
139     }
140     /* Send L2CAP connect rsp */
141     L2CA_ConnectRsp(bd_addr, id, lcid, result, 0);
142 
143     /* if result ok, proceed with connection */
144     if (result == L2CAP_CONN_OK)
145     {
146         /* store LCID */
147         p_lcb->ch_lcid = lcid;
148 
149         /* transition to configuration state */
150         p_lcb->ch_state = AVCT_CH_CFG;
151 
152         /* Send L2CAP config req */
153         memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
154         cfg.mtu_present = TRUE;
155         cfg.mtu = avct_cb.mtu;
156         L2CA_ConfigReq(lcid, &cfg);
157         AVCT_TRACE_DEBUG0("avct_l2c snd Cfg Req");
158     }
159 
160 #if (BT_USE_TRACES == TRUE)
161     if(p_lcb)
162         AVCT_TRACE_DEBUG1("ch_state cni: %d ", p_lcb->ch_state);
163 #endif
164 }
165 
166 /*******************************************************************************
167 **
168 ** Function         avct_l2c_connect_cfm_cback
169 **
170 ** Description      This is the L2CAP connect confirm callback function.
171 **
172 **
173 ** Returns          void
174 **
175 *******************************************************************************/
avct_l2c_connect_cfm_cback(UINT16 lcid,UINT16 result)176 void avct_l2c_connect_cfm_cback(UINT16 lcid, UINT16 result)
177 {
178     tAVCT_LCB       *p_lcb;
179     tL2CAP_CFG_INFO cfg;
180 
181     /* look up lcb for this channel */
182     if ((p_lcb = avct_lcb_by_lcid(lcid)) != NULL)
183     {
184         AVCT_TRACE_DEBUG4("avct_l2c_connect_cfm_cback lcid:0x%x result: %d ch_state: %d, conflict_lcid:0x%x",
185             lcid, result, p_lcb->ch_state, p_lcb->conflict_lcid);
186         /* if in correct state */
187         if (p_lcb->ch_state == AVCT_CH_CONN)
188         {
189             /* if result successful */
190             if (result == L2CAP_CONN_OK)
191             {
192                 /* set channel state */
193                 p_lcb->ch_state = AVCT_CH_CFG;
194 
195                 /* Send L2CAP config req */
196                 memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
197                 cfg.mtu_present = TRUE;
198                 cfg.mtu = avct_cb.mtu;
199                 L2CA_ConfigReq(lcid, &cfg);
200                 AVCT_TRACE_DEBUG0("avct_l2c snd Cfg Req");
201             }
202             /* else failure */
203             else
204             {
205                 AVCT_TRACE_DEBUG1("avct_l2c_connect_cfm_cback conflict_lcid:0x%x", p_lcb->conflict_lcid);
206                 if (p_lcb->conflict_lcid == lcid)
207                     p_lcb->conflict_lcid = 0;
208                 else
209                     avct_lcb_event(p_lcb, AVCT_LCB_LL_CLOSE_EVT, (tAVCT_LCB_EVT *) &result);
210             }
211         }
212         else if (p_lcb->conflict_lcid == lcid)
213         {
214             /* we must be in AVCT_CH_CFG state for the ch_lcid channel */
215             AVCT_TRACE_DEBUG2("avct_l2c_connect_cfm_cback ch_state: %d, conflict_lcid:0x%x", p_lcb->ch_state, p_lcb->conflict_lcid);
216             if (result == L2CAP_CONN_OK)
217             {
218                 /* just in case the peer also accepts our connection - Send L2CAP disconnect req */
219                 L2CA_DisconnectReq(lcid);
220             }
221             p_lcb->conflict_lcid = 0;
222         }
223         AVCT_TRACE_DEBUG1("ch_state cnc: %d ", p_lcb->ch_state);
224     }
225 }
226 
227 /*******************************************************************************
228 **
229 ** Function         avct_l2c_config_cfm_cback
230 **
231 ** Description      This is the L2CAP config confirm callback function.
232 **
233 **
234 ** Returns          void
235 **
236 *******************************************************************************/
avct_l2c_config_cfm_cback(UINT16 lcid,tL2CAP_CFG_INFO * p_cfg)237 void avct_l2c_config_cfm_cback(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg)
238 {
239     tAVCT_LCB       *p_lcb;
240 
241     /* look up lcb for this channel */
242     if ((p_lcb = avct_lcb_by_lcid(lcid)) != NULL)
243     {
244         AVCT_TRACE_DEBUG3("avct_l2c_config_cfm_cback: 0x%x, ch_state: %d, res: %d",
245             lcid, p_lcb->ch_state, p_cfg->result);
246         /* if in correct state */
247         if (p_lcb->ch_state == AVCT_CH_CFG)
248         {
249             /* if result successful */
250             if (p_cfg->result == L2CAP_CFG_OK)
251             {
252                 /* update flags */
253                 p_lcb->ch_flags |= AVCT_L2C_CFG_CFM_DONE;
254 
255                 /* if configuration complete */
256                 if (p_lcb->ch_flags & AVCT_L2C_CFG_IND_DONE)
257                 {
258                     p_lcb->ch_state = AVCT_CH_OPEN;
259                     avct_lcb_event(p_lcb, AVCT_LCB_LL_OPEN_EVT, NULL);
260                 }
261             }
262             /* else failure */
263             else
264             {
265                 AVCT_TRACE_DEBUG1("ERROR avct_l2c_config_cfm_cback L2CA_DisconnectReq %d ", p_lcb->ch_state);
266                 /* store result value */
267                 p_lcb->ch_result = p_cfg->result;
268 
269                 /* Send L2CAP disconnect req */
270                 L2CA_DisconnectReq(lcid);
271             }
272         }
273         AVCT_TRACE_DEBUG1("ch_state cfc: %d ", p_lcb->ch_state);
274     }
275 }
276 
277 /*******************************************************************************
278 **
279 ** Function         avct_l2c_config_ind_cback
280 **
281 ** Description      This is the L2CAP config indication callback function.
282 **
283 **
284 ** Returns          void
285 **
286 *******************************************************************************/
avct_l2c_config_ind_cback(UINT16 lcid,tL2CAP_CFG_INFO * p_cfg)287 void avct_l2c_config_ind_cback(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg)
288 {
289     tAVCT_LCB       *p_lcb;
290 
291     /* look up lcb for this channel */
292     if ((p_lcb = avct_lcb_by_lcid(lcid)) != NULL)
293     {
294         AVCT_TRACE_DEBUG2("avct_l2c_config_ind_cback: 0x%x, ch_state: %d", lcid, p_lcb->ch_state);
295         /* store the mtu in tbl */
296         if (p_cfg->mtu_present)
297         {
298             p_lcb->peer_mtu = p_cfg->mtu;
299         }
300         else
301         {
302             p_lcb->peer_mtu = L2CAP_DEFAULT_MTU;
303         }
304 
305         /* send L2CAP configure response */
306         memset(p_cfg, 0, sizeof(tL2CAP_CFG_INFO));
307         p_cfg->result = L2CAP_CFG_OK;
308         L2CA_ConfigRsp(lcid, p_cfg);
309 
310         /* if first config ind */
311         if ((p_lcb->ch_flags & AVCT_L2C_CFG_IND_DONE) == 0)
312         {
313             /* update flags */
314             p_lcb->ch_flags |= AVCT_L2C_CFG_IND_DONE;
315 
316             /* if configuration complete */
317             if (p_lcb->ch_flags & AVCT_L2C_CFG_CFM_DONE)
318             {
319                 p_lcb->ch_state = AVCT_CH_OPEN;
320                 avct_lcb_event(p_lcb, AVCT_LCB_LL_OPEN_EVT, NULL);
321             }
322         }
323         AVCT_TRACE_DEBUG1("ch_state cfi: %d ", p_lcb->ch_state);
324     }
325 }
326 
327 /*******************************************************************************
328 **
329 ** Function         avct_l2c_disconnect_ind_cback
330 **
331 ** Description      This is the L2CAP disconnect indication callback function.
332 **
333 **
334 ** Returns          void
335 **
336 *******************************************************************************/
avct_l2c_disconnect_ind_cback(UINT16 lcid,BOOLEAN ack_needed)337 void avct_l2c_disconnect_ind_cback(UINT16 lcid, BOOLEAN ack_needed)
338 {
339     tAVCT_LCB       *p_lcb;
340     UINT16          result = AVCT_RESULT_FAIL;
341 
342     /* look up lcb for this channel */
343     if ((p_lcb = avct_lcb_by_lcid(lcid)) != NULL)
344     {
345         AVCT_TRACE_DEBUG2("avct_l2c_disconnect_ind_cback: 0x%x, ch_state: %d", lcid, p_lcb->ch_state);
346         if (ack_needed)
347         {
348             /* send L2CAP disconnect response */
349             L2CA_DisconnectRsp(lcid);
350         }
351 
352         avct_lcb_event(p_lcb, AVCT_LCB_LL_CLOSE_EVT, (tAVCT_LCB_EVT *) &result);
353         AVCT_TRACE_DEBUG1("ch_state di: %d ", p_lcb->ch_state);
354     }
355 }
356 
357 /*******************************************************************************
358 **
359 ** Function         avct_l2c_disconnect_cfm_cback
360 **
361 ** Description      This is the L2CAP disconnect confirm callback function.
362 **
363 **
364 ** Returns          void
365 **
366 *******************************************************************************/
avct_l2c_disconnect_cfm_cback(UINT16 lcid,UINT16 result)367 void avct_l2c_disconnect_cfm_cback(UINT16 lcid, UINT16 result)
368 {
369     tAVCT_LCB       *p_lcb;
370     UINT16          res;
371 
372     /* look up lcb for this channel */
373     if ((p_lcb = avct_lcb_by_lcid(lcid)) != NULL)
374     {
375         AVCT_TRACE_DEBUG3("avct_l2c_disconnect_cfm_cback: 0x%x, ch_state: %d, res: %d",
376             lcid, p_lcb->ch_state, result);
377         /* result value may be previously stored */
378         res = (p_lcb->ch_result != 0) ? p_lcb->ch_result : result;
379         p_lcb->ch_result = 0;
380 
381         avct_lcb_event(p_lcb, AVCT_LCB_LL_CLOSE_EVT, (tAVCT_LCB_EVT *) &res);
382         AVCT_TRACE_DEBUG1("ch_state dc: %d ", p_lcb->ch_state);
383     }
384 }
385 
386 /*******************************************************************************
387 **
388 ** Function         avct_l2c_congestion_ind_cback
389 **
390 ** Description      This is the L2CAP congestion indication callback function.
391 **
392 **
393 ** Returns          void
394 **
395 *******************************************************************************/
avct_l2c_congestion_ind_cback(UINT16 lcid,BOOLEAN is_congested)396 void avct_l2c_congestion_ind_cback(UINT16 lcid, BOOLEAN is_congested)
397 {
398     tAVCT_LCB       *p_lcb;
399 
400     AVCT_TRACE_DEBUG1("avct_l2c_congestion_ind_cback: 0x%x", lcid);
401     /* look up lcb for this channel */
402     if ((p_lcb = avct_lcb_by_lcid(lcid)) != NULL)
403     {
404         avct_lcb_event(p_lcb, AVCT_LCB_LL_CONG_EVT, (tAVCT_LCB_EVT *) &is_congested);
405     }
406 }
407 
408 /*******************************************************************************
409 **
410 ** Function         avct_l2c_data_ind_cback
411 **
412 ** Description      This is the L2CAP data indication callback function.
413 **
414 **
415 ** Returns          void
416 **
417 *******************************************************************************/
avct_l2c_data_ind_cback(UINT16 lcid,BT_HDR * p_buf)418 void avct_l2c_data_ind_cback(UINT16 lcid, BT_HDR *p_buf)
419 {
420     tAVCT_LCB       *p_lcb;
421 
422     AVCT_TRACE_DEBUG1("avct_l2c_data_ind_cback: 0x%x", lcid);
423     /* look up lcb for this channel */
424     if ((p_lcb = avct_lcb_by_lcid(lcid)) != NULL)
425     {
426         avct_lcb_event(p_lcb, AVCT_LCB_LL_MSG_EVT, (tAVCT_LCB_EVT *) &p_buf);
427     }
428     else /* prevent buffer leak */
429     {
430         AVCT_TRACE_WARNING0("ERROR -> avct_l2c_data_ind_cback drop buffer");
431         GKI_freebuf(p_buf);
432     }
433 }
434 
435