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