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 */
38void avct_l2c_connect_ind_cback(BD_ADDR bd_addr, UINT16 lcid, UINT16 psm, UINT8 id);
39void avct_l2c_connect_cfm_cback(UINT16 lcid, UINT16 result);
40void avct_l2c_config_cfm_cback(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg);
41void avct_l2c_config_ind_cback(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg);
42void avct_l2c_disconnect_ind_cback(UINT16 lcid, BOOLEAN ack_needed);
43void avct_l2c_disconnect_cfm_cback(UINT16 lcid, UINT16 result);
44void avct_l2c_congestion_ind_cback(UINT16 lcid, BOOLEAN is_congested);
45void avct_l2c_data_ind_cback(UINT16 lcid, BT_HDR *p_buf);
46
47/* L2CAP callback function structure */
48const 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*******************************************************************************/
72static 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*******************************************************************************/
103void 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*******************************************************************************/
176void 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*******************************************************************************/
237void 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*******************************************************************************/
287void 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*******************************************************************************/
337void 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*******************************************************************************/
367void 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*******************************************************************************/
396void 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*******************************************************************************/
418void 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