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