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