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