1 /******************************************************************************
2 *
3 * Copyright (C) 1999-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 file contains the L2CAP channel state machine
22 *
23 ******************************************************************************/
24
25 #include <stdlib.h>
26 #include <string.h>
27 #include <stdio.h>
28
29 #include "common/bt_target.h"
30 #include "stack/hcidefs.h"
31 #include "stack/hcimsgs.h"
32 #include "stack/l2cdefs.h"
33 #include "l2c_int.h"
34 #include "btm_int.h"
35 #include "stack/btu.h"
36 #include "stack/hcimsgs.h"
37 #include "osi/allocator.h"
38
39 #if (CLASSIC_BT_INCLUDED == TRUE)
40 /********************************************************************************/
41 /* L O C A L F U N C T I O N P R O T O T Y P E S */
42 /********************************************************************************/
43 static void l2c_csm_closed (tL2C_CCB *p_ccb, UINT16 event, void *p_data);
44 static void l2c_csm_orig_w4_sec_comp (tL2C_CCB *p_ccb, UINT16 event, void *p_data);
45 static void l2c_csm_term_w4_sec_comp (tL2C_CCB *p_ccb, UINT16 event, void *p_data);
46 static void l2c_csm_w4_l2cap_connect_rsp (tL2C_CCB *p_ccb, UINT16 event, void *p_data);
47 static void l2c_csm_w4_l2ca_connect_rsp (tL2C_CCB *p_ccb, UINT16 event, void *p_data);
48 static void l2c_csm_config (tL2C_CCB *p_ccb, UINT16 event, void *p_data);
49 static void l2c_csm_open (tL2C_CCB *p_ccb, UINT16 event, void *p_data);
50 static void l2c_csm_w4_l2cap_disconnect_rsp (tL2C_CCB *p_ccb, UINT16 event, void *p_data);
51 static void l2c_csm_w4_l2ca_disconnect_rsp (tL2C_CCB *p_ccb, UINT16 event, void *p_data);
52
53 #if (BT_TRACE_VERBOSE == TRUE)
54 static char *l2c_csm_get_event_name (UINT16 event);
55 #endif
56
57 /*******************************************************************************
58 **
59 ** Function l2c_csm_execute
60 **
61 ** Description This function executes the state machine.
62 **
63 ** Returns void
64 **
65 *******************************************************************************/
l2c_csm_execute(tL2C_CCB * p_ccb,UINT16 event,void * p_data)66 void l2c_csm_execute (tL2C_CCB *p_ccb, UINT16 event, void *p_data)
67 {
68 switch (p_ccb->chnl_state) {
69 case CST_CLOSED:
70 l2c_csm_closed (p_ccb, event, p_data);
71 break;
72
73 case CST_ORIG_W4_SEC_COMP:
74 l2c_csm_orig_w4_sec_comp (p_ccb, event, p_data);
75 break;
76
77 case CST_TERM_W4_SEC_COMP:
78 l2c_csm_term_w4_sec_comp (p_ccb, event, p_data);
79 break;
80
81 case CST_W4_L2CAP_CONNECT_RSP:
82 l2c_csm_w4_l2cap_connect_rsp (p_ccb, event, p_data);
83 break;
84
85 case CST_W4_L2CA_CONNECT_RSP:
86 l2c_csm_w4_l2ca_connect_rsp (p_ccb, event, p_data);
87 break;
88
89 case CST_CONFIG:
90 l2c_csm_config (p_ccb, event, p_data);
91 break;
92
93 case CST_OPEN:
94 l2c_csm_open (p_ccb, event, p_data);
95 break;
96
97 case CST_W4_L2CAP_DISCONNECT_RSP:
98 l2c_csm_w4_l2cap_disconnect_rsp (p_ccb, event, p_data);
99 break;
100
101 case CST_W4_L2CA_DISCONNECT_RSP:
102 l2c_csm_w4_l2ca_disconnect_rsp (p_ccb, event, p_data);
103 break;
104
105 default:
106 L2CAP_TRACE_DEBUG("Unhandled event! event = %d", event);
107 break;
108 }
109 }
110
111 /*******************************************************************************
112 **
113 ** Function l2c_csm_closed
114 **
115 ** Description This function handles events when the channel is in
116 ** CLOSED state. This state exists only when the link is
117 ** being initially established.
118 **
119 ** Returns void
120 **
121 *******************************************************************************/
l2c_csm_closed(tL2C_CCB * p_ccb,UINT16 event,void * p_data)122 static void l2c_csm_closed (tL2C_CCB *p_ccb, UINT16 event, void *p_data)
123 {
124 tL2C_CONN_INFO *p_ci = (tL2C_CONN_INFO *)p_data;
125 UINT16 local_cid = p_ccb->local_cid;
126 tL2CA_DISCONNECT_IND_CB *disconnect_ind;
127 tL2CA_CONNECT_CFM_CB *connect_cfm;
128
129 if (p_ccb->p_rcb == NULL) {
130 #if (BT_TRACE_VERBOSE == TRUE)
131 L2CAP_TRACE_ERROR ("L2CAP - LCID: 0x%04x st: CLOSED evt: %s p_rcb == NULL", p_ccb->local_cid, l2c_csm_get_event_name (event));
132 #else
133 L2CAP_TRACE_ERROR ("L2CAP - LCID: 0x%04x st: CLOSED evt: 0x%04x p_rcb == NULL", p_ccb->local_cid, event);
134 #endif
135 return;
136 }
137
138 #if (L2CAP_UCD_INCLUDED == TRUE)
139 if ( local_cid == L2CAP_CONNECTIONLESS_CID ) {
140 /* check if this event can be processed by UCD */
141 if ( l2c_ucd_process_event (p_ccb, event, p_data) ) {
142 /* The event is processed by UCD state machine */
143 return;
144 }
145 }
146 #endif
147
148 disconnect_ind = p_ccb->p_rcb->api.pL2CA_DisconnectInd_Cb;
149 connect_cfm = p_ccb->p_rcb->api.pL2CA_ConnectCfm_Cb;
150
151 #if (BT_TRACE_VERBOSE == TRUE)
152 L2CAP_TRACE_EVENT ("L2CAP - LCID: 0x%04x st: CLOSED evt: %s", p_ccb->local_cid, l2c_csm_get_event_name (event));
153 #else
154 L2CAP_TRACE_EVENT ("L2CAP - st: CLOSED evt: %d", event);
155 #endif
156
157 switch (event) {
158 case L2CEVT_LP_DISCONNECT_IND: /* Link was disconnected */
159 L2CAP_TRACE_API ("L2CAP - Calling Disconnect_Ind_Cb(), CID: 0x%04x No Conf Needed", p_ccb->local_cid);
160 l2cu_release_ccb (p_ccb);
161 (*disconnect_ind)(local_cid, FALSE);
162 break;
163
164 case L2CEVT_LP_CONNECT_CFM: /* Link came up */
165 p_ccb->chnl_state = CST_ORIG_W4_SEC_COMP;
166 btm_sec_l2cap_access_req (p_ccb->p_lcb->remote_bd_addr, p_ccb->p_rcb->psm,
167 p_ccb->p_lcb->handle, TRUE, &l2c_link_sec_comp, p_ccb);
168 break;
169
170 case L2CEVT_LP_CONNECT_CFM_NEG: /* Link failed */
171 /* Disconnect unless ACL collision and upper layer wants to handle it */
172 if (p_ci->status != HCI_ERR_CONNECTION_EXISTS
173 || !btm_acl_notif_conn_collision(p_ccb->p_lcb->remote_bd_addr)) {
174 L2CAP_TRACE_API ("L2CAP - Calling ConnectCfm_Cb(), CID: 0x%04x Status: %d", p_ccb->local_cid, p_ci->status);
175 l2cu_release_ccb (p_ccb);
176 (*connect_cfm)(local_cid, p_ci->status);
177 }
178 break;
179
180 case L2CEVT_L2CA_CONNECT_REQ: /* API connect request */
181 /* Cancel sniff mode if needed */
182 {
183 tBTM_PM_PWR_MD settings;
184 // btla-specific ++
185 memset((void *)&settings, 0, sizeof(settings));
186 // btla-specific --
187 settings.mode = BTM_PM_MD_ACTIVE;
188 /* COVERITY
189 Event uninit_use_in_call: Using uninitialized value "settings" (field "settings".timeout uninitialized) in call to function "BTM_SetPowerMode" [details]
190 Event uninit_use_in_call: Using uninitialized value "settings.max" in call to function "BTM_SetPowerMode" [details]
191 Event uninit_use_in_call: Using uninitialized value "settings.min" in call to function "BTM_SetPowerMode"
192 // FALSE-POSITIVE error from Coverity test-tool. Please do NOT remove following comment.
193 // coverity[uninit_use_in_call] False-positive: setting the mode to BTM_PM_MD_ACTIVE only uses settings.mode the other data members of tBTM_PM_PWR_MD are ignored
194 */
195 BTM_SetPowerMode (BTM_PM_SET_ONLY_ID, p_ccb->p_lcb->remote_bd_addr, &settings);
196 }
197
198 /* If sec access does not result in started SEC_COM or COMP_NEG are already processed */
199 if (btm_sec_l2cap_access_req (p_ccb->p_lcb->remote_bd_addr, p_ccb->p_rcb->psm,
200 p_ccb->p_lcb->handle, TRUE, &l2c_link_sec_comp, p_ccb) == BTM_CMD_STARTED) {
201 p_ccb->chnl_state = CST_ORIG_W4_SEC_COMP;
202 }
203 break;
204
205 case L2CEVT_SEC_COMP:
206 p_ccb->chnl_state = CST_W4_L2CAP_CONNECT_RSP;
207
208 /* Wait for the info resp in this state before sending connect req (if needed) */
209 if (!p_ccb->p_lcb->w4_info_rsp) {
210 /* Need to have at least one compatible channel to continue */
211 if (!l2c_fcr_chk_chan_modes(p_ccb)) {
212 l2cu_release_ccb (p_ccb);
213 (*p_ccb->p_rcb->api.pL2CA_ConnectCfm_Cb)(local_cid, L2CAP_CONN_NO_LINK);
214 } else {
215 l2cu_send_peer_connect_req (p_ccb);
216 btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_L2CAP_CHNL, L2CAP_CHNL_CONNECT_TOUT);
217 }
218 }
219 break;
220
221 case L2CEVT_SEC_COMP_NEG: /* something is really bad with security */
222 L2CAP_TRACE_API ("L2CAP - Calling ConnectCfm_Cb(), CID: 0x%04x Status: %d", p_ccb->local_cid, L2CAP_CONN_TIMEOUT);
223 l2cu_release_ccb (p_ccb);
224 (*connect_cfm)(local_cid, L2CAP_CONN_SECURITY_BLOCK);
225 break;
226
227 case L2CEVT_L2CAP_CONNECT_REQ: /* Peer connect request */
228 /* stop link timer to avoid race condition between A2MP, Security, and L2CAP */
229 btu_stop_timer (&p_ccb->p_lcb->timer_entry);
230
231 /* Cancel sniff mode if needed */
232 {
233 tBTM_PM_PWR_MD settings;
234 // btla-specific ++
235 memset((void *)&settings, 0, sizeof(settings));
236 // btla-specific --
237 settings.mode = BTM_PM_MD_ACTIVE;
238 /* COVERITY
239 Event uninit_use_in_call: Using uninitialized value "settings" (field "settings".timeout uninitialized) in call to function "BTM_SetPowerMode" [details]
240 Event uninit_use_in_call: Using uninitialized value "settings.max" in call to function "BTM_SetPowerMode" [details]
241 Event uninit_use_in_call: Using uninitialized value "settings.min" in call to function "BTM_SetPowerMode"
242 // FALSE-POSITIVE error from Coverity test-tool. Please do NOT remove following comment.
243 // coverity[uninit_use_in_call] False-positive: setting the mode to BTM_PM_MD_ACTIVE only uses settings.mode the other data members of tBTM_PM_PWR_MD are ignored
244 */
245 BTM_SetPowerMode (BTM_PM_SET_ONLY_ID, p_ccb->p_lcb->remote_bd_addr, &settings);
246 }
247
248 p_ccb->chnl_state = CST_TERM_W4_SEC_COMP;
249 if (btm_sec_l2cap_access_req (p_ccb->p_lcb->remote_bd_addr, p_ccb->p_rcb->psm,
250 p_ccb->p_lcb->handle, FALSE, &l2c_link_sec_comp, p_ccb) == BTM_CMD_STARTED) {
251 /* started the security process, tell the peer to set a longer timer */
252 l2cu_send_peer_connect_rsp(p_ccb, L2CAP_CONN_PENDING, 0);
253 }
254 break;
255
256 case L2CEVT_TIMEOUT:
257 L2CAP_TRACE_API ("L2CAP - Calling ConnectCfm_Cb(), CID: 0x%04x Status: %d", p_ccb->local_cid, L2CAP_CONN_TIMEOUT);
258 l2cu_release_ccb (p_ccb);
259 (*connect_cfm)(local_cid, L2CAP_CONN_TIMEOUT);
260 break;
261
262 case L2CEVT_L2CAP_DATA: /* Peer data packet rcvd */
263 case L2CEVT_L2CA_DATA_WRITE: /* Upper layer data to send */
264 osi_free (p_data);
265 break;
266
267 case L2CEVT_L2CA_DISCONNECT_REQ: /* Upper wants to disconnect */
268 l2cu_release_ccb (p_ccb);
269 break;
270 }
271 }
272
273
274 /*******************************************************************************
275 **
276 ** Function l2c_csm_orig_w4_sec_comp
277 **
278 ** Description This function handles events when the channel is in
279 ** CST_ORIG_W4_SEC_COMP state.
280 **
281 ** Returns void
282 **
283 *******************************************************************************/
l2c_csm_orig_w4_sec_comp(tL2C_CCB * p_ccb,UINT16 event,void * p_data)284 static void l2c_csm_orig_w4_sec_comp (tL2C_CCB *p_ccb, UINT16 event, void *p_data)
285 {
286 tL2CA_DISCONNECT_IND_CB *disconnect_ind = p_ccb->p_rcb->api.pL2CA_DisconnectInd_Cb;
287 tL2CA_CONNECT_CFM_CB *connect_cfm = p_ccb->p_rcb->api.pL2CA_ConnectCfm_Cb;
288 UINT16 local_cid = p_ccb->local_cid;
289
290 #if (BT_TRACE_VERBOSE == TRUE)
291 L2CAP_TRACE_EVENT ("L2CAP - LCID: 0x%04x st: ORIG_W4_SEC_COMP evt: %s", p_ccb->local_cid, l2c_csm_get_event_name (event));
292 #else
293 L2CAP_TRACE_EVENT ("L2CAP - st: ORIG_W4_SEC_COMP evt: %d", event);
294 #endif
295
296 #if (L2CAP_UCD_INCLUDED == TRUE)
297 if ( local_cid == L2CAP_CONNECTIONLESS_CID ) {
298 /* check if this event can be processed by UCD */
299 if ( l2c_ucd_process_event (p_ccb, event, p_data) ) {
300 /* The event is processed by UCD state machine */
301 return;
302 }
303 }
304 #endif
305
306 switch (event) {
307 case L2CEVT_LP_DISCONNECT_IND: /* Link was disconnected */
308 L2CAP_TRACE_API ("L2CAP - Calling Disconnect_Ind_Cb(), CID: 0x%04x No Conf Needed", p_ccb->local_cid);
309 l2cu_release_ccb (p_ccb);
310 (*disconnect_ind)(local_cid, FALSE);
311 break;
312
313 case L2CEVT_SEC_RE_SEND_CMD: /* BTM has enough info to proceed */
314 case L2CEVT_LP_CONNECT_CFM: /* Link came up */
315 btm_sec_l2cap_access_req (p_ccb->p_lcb->remote_bd_addr, p_ccb->p_rcb->psm,
316 p_ccb->p_lcb->handle, TRUE, &l2c_link_sec_comp, p_ccb);
317 break;
318
319 case L2CEVT_SEC_COMP: /* Security completed success */
320 /* Wait for the info resp in this state before sending connect req (if needed) */
321 p_ccb->chnl_state = CST_W4_L2CAP_CONNECT_RSP;
322 if (!p_ccb->p_lcb->w4_info_rsp) {
323 /* Need to have at least one compatible channel to continue */
324 if (!l2c_fcr_chk_chan_modes(p_ccb)) {
325 l2cu_release_ccb (p_ccb);
326 (*connect_cfm)(local_cid, L2CAP_CONN_NO_LINK);
327 } else {
328 btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_L2CAP_CHNL, L2CAP_CHNL_CONNECT_TOUT);
329 l2cu_send_peer_connect_req (p_ccb); /* Start Connection */
330 }
331 }
332 break;
333
334 case L2CEVT_SEC_COMP_NEG:
335 L2CAP_TRACE_API ("L2CAP - Calling ConnectCfm_Cb(), CID: 0x%04x Status: %d", p_ccb->local_cid, HCI_ERR_AUTH_FAILURE);
336
337 /* If last channel immediately disconnect the ACL for better security.
338 Also prevents a race condition between BTM and L2CAP */
339 if ( (p_ccb == p_ccb->p_lcb->ccb_queue.p_first_ccb) && (p_ccb == p_ccb->p_lcb->ccb_queue.p_last_ccb) ) {
340 p_ccb->p_lcb->idle_timeout = 0;
341 }
342
343 l2cu_release_ccb (p_ccb);
344 (*connect_cfm)(local_cid, HCI_ERR_AUTH_FAILURE);
345 break;
346
347 case L2CEVT_L2CA_DATA_WRITE: /* Upper layer data to send */
348 case L2CEVT_L2CAP_DATA: /* Peer data packet rcvd */
349 osi_free (p_data);
350 break;
351
352 case L2CEVT_L2CA_DISCONNECT_REQ: /* Upper wants to disconnect */
353 /* Tell security manager to abort */
354 btm_sec_abort_access_req (p_ccb->p_lcb->remote_bd_addr);
355
356 l2cu_release_ccb (p_ccb);
357 break;
358 }
359 }
360
361
362 /*******************************************************************************
363 **
364 ** Function l2c_csm_term_w4_sec_comp
365 **
366 ** Description This function handles events when the channel is in
367 ** CST_TERM_W4_SEC_COMP state.
368 **
369 ** Returns void
370 **
371 *******************************************************************************/
l2c_csm_term_w4_sec_comp(tL2C_CCB * p_ccb,UINT16 event,void * p_data)372 static void l2c_csm_term_w4_sec_comp (tL2C_CCB *p_ccb, UINT16 event, void *p_data)
373 {
374 #if (BT_TRACE_VERBOSE == TRUE)
375 L2CAP_TRACE_EVENT ("L2CAP - LCID: 0x%04x st: TERM_W4_SEC_COMP evt: %s", p_ccb->local_cid, l2c_csm_get_event_name (event));
376 #else
377 L2CAP_TRACE_EVENT ("L2CAP - st: TERM_W4_SEC_COMP evt: %d", event);
378 #endif
379
380 #if (L2CAP_UCD_INCLUDED == TRUE)
381 if ( p_ccb->local_cid == L2CAP_CONNECTIONLESS_CID ) {
382 /* check if this event can be processed by UCD */
383 if ( l2c_ucd_process_event (p_ccb, event, p_data) ) {
384 /* The event is processed by UCD state machine */
385 return;
386 }
387 }
388 #endif
389
390 switch (event) {
391 case L2CEVT_LP_DISCONNECT_IND: /* Link was disconnected */
392 /* Tell security manager to abort */
393 btm_sec_abort_access_req (p_ccb->p_lcb->remote_bd_addr);
394
395 l2cu_release_ccb (p_ccb);
396 break;
397
398 case L2CEVT_SEC_COMP:
399 p_ccb->chnl_state = CST_W4_L2CA_CONNECT_RSP;
400
401 /* Wait for the info resp in next state before sending connect ind (if needed) */
402 if (!p_ccb->p_lcb->w4_info_rsp) {
403 /* Don't need to get info from peer or already retrieved so continue */
404 btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_L2CAP_CHNL, L2CAP_CHNL_CONNECT_TOUT);
405 L2CAP_TRACE_API ("L2CAP - Calling Connect_Ind_Cb(), CID: 0x%04x", p_ccb->local_cid);
406
407 (*p_ccb->p_rcb->api.pL2CA_ConnectInd_Cb) (p_ccb->p_lcb->remote_bd_addr, p_ccb->local_cid,
408 p_ccb->p_rcb->psm, p_ccb->remote_id);
409 } else {
410 /*
411 ** L2CAP Connect Response will be sent out by 3 sec timer expiration
412 ** because Bluesoleil doesn't respond to L2CAP Information Request.
413 ** Bluesoleil seems to disconnect ACL link as failure case, because
414 ** it takes too long (4~7secs) to get response.
415 ** product version : Bluesoleil 2.1.1.0 EDR Release 060123
416 ** stack version : 05.04.11.20060119
417 */
418
419 /* Waiting for the info resp, tell the peer to set a longer timer */
420 l2cu_send_peer_connect_rsp(p_ccb, L2CAP_CONN_PENDING, 0);
421 }
422 break;
423
424 case L2CEVT_SEC_COMP_NEG:
425 if (((tL2C_CONN_INFO *)p_data)->status == BTM_DELAY_CHECK) {
426 /* start a timer - encryption change not received before L2CAP connect req */
427 btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_L2CAP_CHNL, L2CAP_DELAY_CHECK_SM4);
428 } else {
429 l2cu_send_peer_connect_rsp (p_ccb, L2CAP_CONN_SECURITY_BLOCK, 0);
430 l2cu_release_ccb (p_ccb);
431 }
432 break;
433
434 case L2CEVT_L2CA_DATA_WRITE: /* Upper layer data to send */
435 case L2CEVT_L2CAP_DATA: /* Peer data packet rcvd */
436 osi_free (p_data);
437 break;
438
439 case L2CEVT_L2CA_DISCONNECT_REQ: /* Upper wants to disconnect */
440 l2cu_release_ccb (p_ccb);
441 break;
442
443 case L2CEVT_L2CAP_DISCONNECT_REQ: /* Peer disconnected request */
444 l2cu_send_peer_disc_rsp (p_ccb->p_lcb, p_ccb->remote_id, p_ccb->local_cid, p_ccb->remote_cid);
445
446 /* Tell security manager to abort */
447 btm_sec_abort_access_req (p_ccb->p_lcb->remote_bd_addr);
448
449 l2cu_release_ccb (p_ccb);
450 break;
451
452 case L2CEVT_TIMEOUT:
453 /* SM4 related. */
454 if (!btsnd_hcic_disconnect (p_ccb->p_lcb->handle, HCI_ERR_AUTH_FAILURE)) {
455 L2CAP_TRACE_API ("L2CAP - Calling btsnd_hcic_disconnect for handle %i failed", p_ccb->p_lcb->handle);
456 btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_L2CAP_CHNL, 1);
457 }
458 break;
459
460 case L2CEVT_SEC_RE_SEND_CMD: /* BTM has enough info to proceed */
461 btm_sec_l2cap_access_req (p_ccb->p_lcb->remote_bd_addr, p_ccb->p_rcb->psm,
462 p_ccb->p_lcb->handle, FALSE, &l2c_link_sec_comp, p_ccb);
463 break;
464 }
465 }
466
467
468 /*******************************************************************************
469 **
470 ** Function l2c_csm_w4_l2cap_connect_rsp
471 **
472 ** Description This function handles events when the channel is in
473 ** CST_W4_L2CAP_CONNECT_RSP state.
474 **
475 ** Returns void
476 **
477 *******************************************************************************/
l2c_csm_w4_l2cap_connect_rsp(tL2C_CCB * p_ccb,UINT16 event,void * p_data)478 static void l2c_csm_w4_l2cap_connect_rsp (tL2C_CCB *p_ccb, UINT16 event, void *p_data)
479 {
480 tL2C_CONN_INFO *p_ci = (tL2C_CONN_INFO *)p_data;
481 tL2CA_DISCONNECT_IND_CB *disconnect_ind = p_ccb->p_rcb->api.pL2CA_DisconnectInd_Cb;
482 tL2CA_CONNECT_CFM_CB *connect_cfm = p_ccb->p_rcb->api.pL2CA_ConnectCfm_Cb;
483 UINT16 local_cid = p_ccb->local_cid;
484
485 #if (BT_TRACE_VERBOSE == TRUE)
486 L2CAP_TRACE_EVENT ("L2CAP - LCID: 0x%04x st: W4_L2CAP_CON_RSP evt: %s", p_ccb->local_cid, l2c_csm_get_event_name (event));
487 #else
488 L2CAP_TRACE_EVENT ("L2CAP - st: W4_L2CAP_CON_RSP evt: %d", event);
489 #endif
490
491 switch (event) {
492 case L2CEVT_LP_DISCONNECT_IND: /* Link was disconnected */
493 /* Send disc indication unless peer to peer race condition AND normal disconnect */
494 /* *((UINT8 *)p_data) != HCI_ERR_PEER_USER happens when peer device try to disconnect for normal reason */
495 p_ccb->chnl_state = CST_CLOSED;
496 if ((p_ccb->flags & CCB_FLAG_NO_RETRY) || !p_data || (*((UINT8 *)p_data) != HCI_ERR_PEER_USER)) {
497 L2CAP_TRACE_API ("L2CAP - Calling Disconnect_Ind_Cb(), CID: 0x%04x No Conf Needed",
498 p_ccb->local_cid);
499 l2cu_release_ccb (p_ccb);
500 (*disconnect_ind)(local_cid, FALSE);
501 }
502 p_ccb->flags |= CCB_FLAG_NO_RETRY;
503 break;
504
505 case L2CEVT_L2CAP_CONNECT_RSP: /* Got peer connect confirm */
506 p_ccb->remote_cid = p_ci->remote_cid;
507 p_ccb->chnl_state = CST_CONFIG;
508 btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_L2CAP_CHNL, L2CAP_CHNL_CFG_TIMEOUT);
509 L2CAP_TRACE_API ("L2CAP - Calling Connect_Cfm_Cb(), CID: 0x%04x, Success", p_ccb->local_cid);
510
511 (*p_ccb->p_rcb->api.pL2CA_ConnectCfm_Cb)(local_cid, L2CAP_CONN_OK);
512 break;
513
514 case L2CEVT_L2CAP_CONNECT_RSP_PND: /* Got peer connect pending */
515 p_ccb->remote_cid = p_ci->remote_cid;
516 btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_L2CAP_CHNL, L2CAP_CHNL_CONNECT_TOUT_EXT);
517 if (p_ccb->p_rcb->api.pL2CA_ConnectPnd_Cb) {
518 L2CAP_TRACE_API ("L2CAP - Calling Connect_Pnd_Cb(), CID: 0x%04x", p_ccb->local_cid);
519 (*p_ccb->p_rcb->api.pL2CA_ConnectPnd_Cb)(p_ccb->local_cid);
520 }
521 break;
522
523 case L2CEVT_L2CAP_CONNECT_RSP_NEG: /* Peer rejected connection */
524 L2CAP_TRACE_API ("L2CAP - Calling Connect_Cfm_Cb(), CID: 0x%04x, Failure Code: %d", p_ccb->local_cid, p_ci->l2cap_result);
525 l2cu_release_ccb (p_ccb);
526 (*connect_cfm)(local_cid, p_ci->l2cap_result);
527 break;
528
529 case L2CEVT_TIMEOUT:
530 L2CAP_TRACE_API ("L2CAP - Calling Connect_Cfm_Cb(), CID: 0x%04x, Timeout", p_ccb->local_cid);
531 l2cu_release_ccb (p_ccb);
532 (*connect_cfm)(local_cid, L2CAP_CONN_TIMEOUT);
533 break;
534
535 case L2CEVT_L2CA_DISCONNECT_REQ: /* Upper wants to disconnect */
536 /* If we know peer CID from connect pending, we can send disconnect */
537 if (p_ccb->remote_cid != 0) {
538 l2cu_send_peer_disc_req (p_ccb);
539 p_ccb->chnl_state = CST_W4_L2CAP_DISCONNECT_RSP;
540 btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_L2CAP_CHNL, L2CAP_CHNL_DISCONNECT_TOUT);
541 } else {
542 l2cu_release_ccb (p_ccb);
543 }
544 break;
545
546 case L2CEVT_L2CA_DATA_WRITE: /* Upper layer data to send */
547 case L2CEVT_L2CAP_DATA: /* Peer data packet rcvd */
548 osi_free (p_data);
549 break;
550
551 case L2CEVT_L2CAP_INFO_RSP:
552 /* Need to have at least one compatible channel to continue */
553 if (!l2c_fcr_chk_chan_modes(p_ccb)) {
554 l2cu_release_ccb (p_ccb);
555 (*connect_cfm)(local_cid, L2CAP_CONN_NO_LINK);
556 } else {
557 /* We have feature info, so now send peer connect request */
558 btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_L2CAP_CHNL, L2CAP_CHNL_CONNECT_TOUT);
559 l2cu_send_peer_connect_req (p_ccb); /* Start Connection */
560 }
561 break;
562 }
563 }
564
565
566 /*******************************************************************************
567 **
568 ** Function l2c_csm_w4_l2ca_connect_rsp
569 **
570 ** Description This function handles events when the channel is in
571 ** CST_W4_L2CA_CONNECT_RSP state.
572 **
573 ** Returns void
574 **
575 *******************************************************************************/
l2c_csm_w4_l2ca_connect_rsp(tL2C_CCB * p_ccb,UINT16 event,void * p_data)576 static void l2c_csm_w4_l2ca_connect_rsp (tL2C_CCB *p_ccb, UINT16 event, void *p_data)
577 {
578 tL2C_CONN_INFO *p_ci;
579 tL2CA_DISCONNECT_IND_CB *disconnect_ind = p_ccb->p_rcb->api.pL2CA_DisconnectInd_Cb;
580 UINT16 local_cid = p_ccb->local_cid;
581
582 #if (BT_TRACE_VERBOSE == TRUE)
583 L2CAP_TRACE_EVENT ("L2CAP - LCID: 0x%04x st: W4_L2CA_CON_RSP evt: %s", p_ccb->local_cid, l2c_csm_get_event_name (event));
584 #else
585 L2CAP_TRACE_EVENT ("L2CAP - st: W4_L2CA_CON_RSP evt: %d", event);
586 #endif
587
588 switch (event) {
589 case L2CEVT_LP_DISCONNECT_IND: /* Link was disconnected */
590 L2CAP_TRACE_API ("L2CAP - Calling Disconnect_Ind_Cb(), CID: 0x%04x No Conf Needed", p_ccb->local_cid);
591 l2cu_release_ccb (p_ccb);
592 (*disconnect_ind)(local_cid, FALSE);
593 break;
594
595 case L2CEVT_L2CA_CONNECT_RSP:
596 p_ci = (tL2C_CONN_INFO *)p_data;
597
598 /* Result should be OK or PENDING */
599 if ((!p_ci) || (p_ci->l2cap_result == L2CAP_CONN_OK)) {
600 l2cu_send_peer_connect_rsp (p_ccb, L2CAP_CONN_OK, 0);
601 p_ccb->chnl_state = CST_CONFIG;
602 btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_L2CAP_CHNL, L2CAP_CHNL_CFG_TIMEOUT);
603 } else {
604 /* If pending, stay in same state and start extended timer */
605 l2cu_send_peer_connect_rsp (p_ccb, p_ci->l2cap_result, p_ci->l2cap_status);
606 btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_L2CAP_CHNL, L2CAP_CHNL_CONNECT_TOUT_EXT);
607 }
608 break;
609
610 case L2CEVT_L2CA_CONNECT_RSP_NEG:
611 p_ci = (tL2C_CONN_INFO *)p_data;
612 l2cu_send_peer_connect_rsp (p_ccb, p_ci->l2cap_result, p_ci->l2cap_status);
613 l2cu_release_ccb (p_ccb);
614 break;
615
616 case L2CEVT_TIMEOUT:
617 l2cu_send_peer_connect_rsp (p_ccb, L2CAP_CONN_NO_PSM, 0);
618 L2CAP_TRACE_API ("L2CAP - Calling Disconnect_Ind_Cb(), CID: 0x%04x No Conf Needed", p_ccb->local_cid);
619 l2cu_release_ccb (p_ccb);
620 (*disconnect_ind)(local_cid, FALSE);
621 break;
622
623 case L2CEVT_L2CA_DATA_WRITE: /* Upper layer data to send */
624 case L2CEVT_L2CAP_DATA: /* Peer data packet rcvd */
625 osi_free (p_data);
626 break;
627
628 case L2CEVT_L2CA_DISCONNECT_REQ: /* Upper wants to disconnect */
629 l2cu_send_peer_disc_req (p_ccb);
630 p_ccb->chnl_state = CST_W4_L2CAP_DISCONNECT_RSP;
631 btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_L2CAP_CHNL, L2CAP_CHNL_DISCONNECT_TOUT);
632 break;
633
634 case L2CEVT_L2CAP_INFO_RSP:
635 /* We have feature info, so now give the upper layer connect IND */
636 btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_L2CAP_CHNL, L2CAP_CHNL_CONNECT_TOUT);
637 L2CAP_TRACE_API ("L2CAP - Calling Connect_Ind_Cb(), CID: 0x%04x", p_ccb->local_cid);
638
639 (*p_ccb->p_rcb->api.pL2CA_ConnectInd_Cb) (p_ccb->p_lcb->remote_bd_addr,
640 p_ccb->local_cid,
641 p_ccb->p_rcb->psm,
642 p_ccb->remote_id);
643 break;
644 }
645 }
646
647
648 /*******************************************************************************
649 **
650 ** Function l2c_csm_config
651 **
652 ** Description This function handles events when the channel is in
653 ** CONFIG state.
654 **
655 ** Returns void
656 **
657 *******************************************************************************/
l2c_csm_config(tL2C_CCB * p_ccb,UINT16 event,void * p_data)658 static void l2c_csm_config (tL2C_CCB *p_ccb, UINT16 event, void *p_data)
659 {
660 tL2CAP_CFG_INFO *p_cfg = (tL2CAP_CFG_INFO *)p_data;
661 tL2CA_DISCONNECT_IND_CB *disconnect_ind = p_ccb->p_rcb->api.pL2CA_DisconnectInd_Cb;
662 UINT16 local_cid = p_ccb->local_cid;
663 UINT8 cfg_result;
664
665 #if (BT_TRACE_VERBOSE == TRUE)
666 L2CAP_TRACE_EVENT ("L2CAP - LCID: 0x%04x st: CONFIG evt: %s", p_ccb->local_cid, l2c_csm_get_event_name (event));
667 #else
668 L2CAP_TRACE_EVENT ("L2CAP - st: CONFIG evt: %d", event);
669 #endif
670
671 switch (event) {
672 case L2CEVT_LP_DISCONNECT_IND: /* Link was disconnected */
673 L2CAP_TRACE_API ("L2CAP - Calling Disconnect_Ind_Cb(), CID: 0x%04x No Conf Needed", p_ccb->local_cid);
674 l2cu_release_ccb (p_ccb);
675 (*disconnect_ind)(local_cid, FALSE);
676 break;
677
678 case L2CEVT_L2CAP_CONFIG_REQ: /* Peer config request */
679
680 if ((cfg_result = l2cu_process_peer_cfg_req (p_ccb, p_cfg)) == L2CAP_PEER_CFG_OK) {
681 L2CAP_TRACE_EVENT ("L2CAP - Calling Config_Req_Cb(), CID: 0x%04x, C-bit %d",
682 p_ccb->local_cid, (p_cfg->flags & L2CAP_CFG_FLAGS_MASK_CONT));
683 (*p_ccb->p_rcb->api.pL2CA_ConfigInd_Cb)(p_ccb->local_cid, p_cfg);
684 } else if (cfg_result == L2CAP_PEER_CFG_DISCONNECT) {
685 /* Disconnect if channels are incompatible */
686 L2CAP_TRACE_EVENT ("L2CAP - incompatible configurations disconnect");
687 l2cu_disconnect_chnl (p_ccb);
688 } else { /* Return error to peer so he can renegotiate if possible */
689 L2CAP_TRACE_EVENT ("L2CAP - incompatible configurations trying reconfig");
690 l2cu_send_peer_config_rsp (p_ccb, p_cfg);
691 }
692 break;
693
694 case L2CEVT_L2CAP_CONFIG_RSP: /* Peer config response */
695 l2cu_process_peer_cfg_rsp (p_ccb, p_cfg);
696
697 if (p_cfg->result != L2CAP_CFG_PENDING) {
698 /* TBD: When config options grow beyong minimum MTU (48 bytes)
699 * logic needs to be added to handle responses with
700 * continuation bit set in flags field.
701 * 1. Send additional config request out until C-bit is cleared in response
702 */
703 p_ccb->config_done |= OB_CFG_DONE;
704
705 if (p_ccb->config_done & IB_CFG_DONE) {
706 /* Verify two sides are in compatible modes before continuing */
707 if (p_ccb->our_cfg.fcr.mode != p_ccb->peer_cfg.fcr.mode) {
708 l2cu_send_peer_disc_req (p_ccb);
709 L2CAP_TRACE_WARNING ("L2CAP - Calling Disconnect_Ind_Cb(Incompatible CFG), CID: 0x%04x No Conf Needed", p_ccb->local_cid);
710 l2cu_release_ccb (p_ccb);
711 (*disconnect_ind)(local_cid, FALSE);
712 break;
713 }
714
715 p_ccb->config_done |= RECONFIG_FLAG;
716 p_ccb->chnl_state = CST_OPEN;
717 l2c_link_adjust_chnl_allocation ();
718 btu_stop_timer (&p_ccb->timer_entry);
719
720 /* If using eRTM and waiting for an ACK, restart the ACK timer */
721 if (p_ccb->fcrb.wait_ack) {
722 l2c_fcr_start_timer(p_ccb);
723 }
724
725 /*
726 ** check p_ccb->our_cfg.fcr.mon_tout and p_ccb->our_cfg.fcr.rtrans_tout
727 ** we may set them to zero when sending config request during renegotiation
728 */
729 if ((p_ccb->our_cfg.fcr.mode == L2CAP_FCR_ERTM_MODE)
730 && ((p_ccb->our_cfg.fcr.mon_tout == 0) || (p_ccb->our_cfg.fcr.rtrans_tout))) {
731 l2c_fcr_adj_monitor_retran_timeout (p_ccb);
732 }
733
734 #if (L2CAP_ERTM_STATS == TRUE)
735 p_ccb->fcrb.connect_tick_count = osi_time_get_os_boottime_ms();
736 #endif
737 /* See if we can forward anything on the hold queue */
738 if (!fixed_queue_is_empty(p_ccb->xmit_hold_q)) {
739 l2c_link_check_send_pkts (p_ccb->p_lcb, NULL, NULL);
740 }
741 }
742 }
743
744 L2CAP_TRACE_API ("L2CAP - Calling Config_Rsp_Cb(), CID: 0x%04x", p_ccb->local_cid);
745 (*p_ccb->p_rcb->api.pL2CA_ConfigCfm_Cb)(p_ccb->local_cid, p_cfg);
746 break;
747
748 case L2CEVT_L2CAP_CONFIG_RSP_NEG: /* Peer config error rsp */
749 /* Disable the Timer */
750 btu_stop_timer (&p_ccb->timer_entry);
751
752 /* If failure was channel mode try to renegotiate */
753 if (l2c_fcr_renegotiate_chan(p_ccb, p_cfg) == FALSE) {
754 L2CAP_TRACE_API ("L2CAP - Calling Config_Rsp_Cb(), CID: 0x%04x, Failure: %d", p_ccb->local_cid, p_cfg->result);
755 (*p_ccb->p_rcb->api.pL2CA_ConfigCfm_Cb)(p_ccb->local_cid, p_cfg);
756 }
757 break;
758
759 case L2CEVT_L2CAP_DISCONNECT_REQ: /* Peer disconnected request */
760 btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_L2CAP_CHNL, L2CAP_CHNL_DISCONNECT_TOUT);
761 p_ccb->chnl_state = CST_W4_L2CA_DISCONNECT_RSP;
762 L2CAP_TRACE_API ("L2CAP - Calling Disconnect_Ind_Cb(), CID: 0x%04x Conf Needed", p_ccb->local_cid);
763 (*p_ccb->p_rcb->api.pL2CA_DisconnectInd_Cb)(p_ccb->local_cid, TRUE);
764 break;
765
766 case L2CEVT_L2CA_CONFIG_REQ: /* Upper layer config req */
767 l2cu_process_our_cfg_req (p_ccb, p_cfg);
768 l2cu_send_peer_config_req (p_ccb, p_cfg);
769 btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_L2CAP_CHNL, L2CAP_CHNL_CFG_TIMEOUT);
770 break;
771
772 case L2CEVT_L2CA_CONFIG_RSP: /* Upper layer config rsp */
773 l2cu_process_our_cfg_rsp (p_ccb, p_cfg);
774
775 /* Not finished if continuation flag is set */
776 if ( (p_cfg->flags & L2CAP_CFG_FLAGS_MASK_CONT) || (p_cfg->result == L2CAP_CFG_PENDING) ) {
777 /* Send intermediate response; remain in cfg state */
778 l2cu_send_peer_config_rsp (p_ccb, p_cfg);
779 break;
780 }
781
782 /* Local config done; clear cached configuration in case reconfig takes place later */
783 p_ccb->peer_cfg.mtu_present = FALSE;
784 p_ccb->peer_cfg.flush_to_present = FALSE;
785 p_ccb->peer_cfg.qos_present = FALSE;
786
787 p_ccb->config_done |= IB_CFG_DONE;
788
789 if (p_ccb->config_done & OB_CFG_DONE) {
790 /* Verify two sides are in compatible modes before continuing */
791 if (p_ccb->our_cfg.fcr.mode != p_ccb->peer_cfg.fcr.mode) {
792 l2cu_send_peer_disc_req (p_ccb);
793 L2CAP_TRACE_WARNING ("L2CAP - Calling Disconnect_Ind_Cb(Incompatible CFG), CID: 0x%04x No Conf Needed", p_ccb->local_cid);
794 l2cu_release_ccb (p_ccb);
795 (*disconnect_ind)(local_cid, FALSE);
796 break;
797 }
798
799 p_ccb->config_done |= RECONFIG_FLAG;
800 p_ccb->chnl_state = CST_OPEN;
801 l2c_link_adjust_chnl_allocation ();
802 btu_stop_timer (&p_ccb->timer_entry);
803 }
804
805 l2cu_send_peer_config_rsp (p_ccb, p_cfg);
806
807 /* If using eRTM and waiting for an ACK, restart the ACK timer */
808 if (p_ccb->fcrb.wait_ack) {
809 l2c_fcr_start_timer(p_ccb);
810 }
811
812 #if (L2CAP_ERTM_STATS == TRUE)
813 p_ccb->fcrb.connect_tick_count = osi_time_get_os_boottime_ms();
814 #endif
815
816 /* See if we can forward anything on the hold queue */
817 if ( (p_ccb->chnl_state == CST_OPEN) &&
818 (!fixed_queue_is_empty(p_ccb->xmit_hold_q))) {
819 l2c_link_check_send_pkts (p_ccb->p_lcb, NULL, NULL);
820 }
821 break;
822
823 case L2CEVT_L2CA_CONFIG_RSP_NEG: /* Upper layer config reject */
824 l2cu_send_peer_config_rsp (p_ccb, p_cfg);
825 btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_L2CAP_CHNL, L2CAP_CHNL_CFG_TIMEOUT);
826 break;
827
828 case L2CEVT_L2CA_DISCONNECT_REQ: /* Upper wants to disconnect */
829 l2cu_send_peer_disc_req (p_ccb);
830 p_ccb->chnl_state = CST_W4_L2CAP_DISCONNECT_RSP;
831 btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_L2CAP_CHNL, L2CAP_CHNL_DISCONNECT_TOUT);
832 break;
833
834 case L2CEVT_L2CAP_DATA: /* Peer data packet rcvd */
835 L2CAP_TRACE_API ("L2CAP - Calling DataInd_Cb(), CID: 0x%04x", p_ccb->local_cid);
836 #if (L2CAP_NUM_FIXED_CHNLS > 0)
837 if (p_ccb->local_cid >= L2CAP_FIRST_FIXED_CHNL &&
838 p_ccb->local_cid <= L2CAP_LAST_FIXED_CHNL) {
839 if (p_ccb->local_cid < L2CAP_BASE_APPL_CID) {
840 if (l2cb.fixed_reg[p_ccb->local_cid - L2CAP_FIRST_FIXED_CHNL].pL2CA_FixedData_Cb) {
841 (*l2cb.fixed_reg[p_ccb->local_cid - L2CAP_FIRST_FIXED_CHNL].pL2CA_FixedData_Cb)
842 (p_ccb->local_cid, p_ccb->p_lcb->remote_bd_addr, (BT_HDR *)p_data);
843 } else {
844 osi_free (p_data);
845 }
846 break;
847 }
848 }
849 #endif
850 (*p_ccb->p_rcb->api.pL2CA_DataInd_Cb)(p_ccb->local_cid, (BT_HDR *)p_data);
851 break;
852
853 case L2CEVT_L2CA_DATA_WRITE: /* Upper layer data to send */
854 if (p_ccb->config_done & OB_CFG_DONE) {
855 l2c_enqueue_peer_data (p_ccb, (BT_HDR *)p_data);
856 } else {
857 osi_free (p_data);
858 }
859 break;
860
861 case L2CEVT_TIMEOUT:
862 l2cu_send_peer_disc_req (p_ccb);
863 L2CAP_TRACE_API ("L2CAP - Calling Disconnect_Ind_Cb(), CID: 0x%04x No Conf Needed",
864 p_ccb->local_cid);
865 l2cu_release_ccb (p_ccb);
866 (*disconnect_ind)(local_cid, FALSE);
867 break;
868 }
869 }
870
871
872 /*******************************************************************************
873 **
874 ** Function l2c_csm_open
875 **
876 ** Description This function handles events when the channel is in
877 ** OPEN state.
878 **
879 ** Returns void
880 **
881 *******************************************************************************/
l2c_csm_open(tL2C_CCB * p_ccb,UINT16 event,void * p_data)882 static void l2c_csm_open (tL2C_CCB *p_ccb, UINT16 event, void *p_data)
883 {
884 UINT16 local_cid = p_ccb->local_cid;
885 tL2CAP_CFG_INFO *p_cfg;
886 tL2C_CHNL_STATE tempstate;
887 UINT8 tempcfgdone;
888 UINT8 cfg_result;
889
890 #if (BT_TRACE_VERBOSE == TRUE)
891 L2CAP_TRACE_EVENT ("L2CAP - LCID: 0x%04x st: OPEN evt: %s",
892 p_ccb->local_cid, l2c_csm_get_event_name (event));
893 #else
894 L2CAP_TRACE_EVENT ("L2CAP - st: OPEN evt: %d", event);
895 #endif
896
897 #if (L2CAP_UCD_INCLUDED == TRUE)
898 if ( local_cid == L2CAP_CONNECTIONLESS_CID ) {
899 /* check if this event can be processed by UCD */
900 if ( l2c_ucd_process_event (p_ccb, event, p_data) ) {
901 /* The event is processed by UCD state machine */
902 return;
903 }
904 }
905 #endif
906
907 switch (event) {
908 case L2CEVT_LP_DISCONNECT_IND: /* Link was disconnected */
909 L2CAP_TRACE_API ("L2CAP - Calling Disconnect_Ind_Cb(), CID: 0x%04x No Conf Needed",
910 p_ccb->local_cid);
911 l2cu_release_ccb (p_ccb);
912 if (p_ccb->p_rcb) {
913 (*p_ccb->p_rcb->api.pL2CA_DisconnectInd_Cb)(local_cid, FALSE);
914 }
915 break;
916
917 case L2CEVT_LP_QOS_VIOLATION_IND: /* QOS violation */
918 /* Tell upper layer. If service guaranteed, then clear the channel */
919 if (p_ccb->p_rcb->api.pL2CA_QoSViolationInd_Cb) {
920 (*p_ccb->p_rcb->api.pL2CA_QoSViolationInd_Cb)(p_ccb->p_lcb->remote_bd_addr);
921 }
922 break;
923
924 case L2CEVT_L2CAP_CONFIG_REQ: /* Peer config request */
925 p_cfg = (tL2CAP_CFG_INFO *)p_data;
926
927 tempstate = p_ccb->chnl_state;
928 tempcfgdone = p_ccb->config_done;
929 p_ccb->chnl_state = CST_CONFIG;
930 p_ccb->config_done &= ~CFG_DONE_MASK;
931
932 btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_L2CAP_CHNL, L2CAP_CHNL_CFG_TIMEOUT);
933
934 if ((cfg_result = l2cu_process_peer_cfg_req (p_ccb, p_cfg)) == L2CAP_PEER_CFG_OK) {
935 (*p_ccb->p_rcb->api.pL2CA_ConfigInd_Cb)(p_ccb->local_cid, p_cfg);
936 }
937
938 /* Error in config parameters: reset state and config flag */
939 else if (cfg_result == L2CAP_PEER_CFG_UNACCEPTABLE) {
940 btu_stop_timer(&p_ccb->timer_entry);
941 p_ccb->chnl_state = tempstate;
942 p_ccb->config_done = tempcfgdone;
943 l2cu_send_peer_config_rsp (p_ccb, p_cfg);
944 } else { /* L2CAP_PEER_CFG_DISCONNECT */
945 /* Disconnect if channels are incompatible
946 * Note this should not occur if reconfigure
947 * since this should have never passed original config.
948 */
949 l2cu_disconnect_chnl (p_ccb);
950 }
951 break;
952
953 case L2CEVT_L2CAP_DISCONNECT_REQ: /* Peer disconnected request */
954 // btla-specific ++
955 /* Make sure we are not in sniff mode */
956 {
957 tBTM_PM_PWR_MD settings;
958 memset((void *)&settings, 0, sizeof(settings));
959 settings.mode = BTM_PM_MD_ACTIVE;
960 BTM_SetPowerMode (BTM_PM_SET_ONLY_ID, p_ccb->p_lcb->remote_bd_addr, &settings);
961 }
962 // btla-specific --
963
964 p_ccb->chnl_state = CST_W4_L2CA_DISCONNECT_RSP;
965 btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_L2CAP_CHNL, L2CAP_CHNL_DISCONNECT_TOUT);
966 L2CAP_TRACE_API ("L2CAP - Calling Disconnect_Ind_Cb(), CID: 0x%04x Conf Needed", p_ccb->local_cid);
967 (*p_ccb->p_rcb->api.pL2CA_DisconnectInd_Cb)(p_ccb->local_cid, TRUE);
968 break;
969
970 case L2CEVT_L2CAP_DATA: /* Peer data packet rcvd */
971 if ((p_ccb->p_rcb) && (p_ccb->p_rcb->api.pL2CA_DataInd_Cb)) {
972 (*p_ccb->p_rcb->api.pL2CA_DataInd_Cb)(p_ccb->local_cid, (BT_HDR *)p_data);
973 }
974 break;
975
976 case L2CEVT_L2CA_DISCONNECT_REQ: /* Upper wants to disconnect */
977 /* Make sure we are not in sniff mode */
978 {
979 tBTM_PM_PWR_MD settings;
980 memset((void *)&settings, 0, sizeof(settings));
981 settings.mode = BTM_PM_MD_ACTIVE;
982 BTM_SetPowerMode (BTM_PM_SET_ONLY_ID, p_ccb->p_lcb->remote_bd_addr, &settings);
983 }
984
985 l2cu_send_peer_disc_req (p_ccb);
986 p_ccb->chnl_state = CST_W4_L2CAP_DISCONNECT_RSP;
987 btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_L2CAP_CHNL, L2CAP_CHNL_DISCONNECT_TOUT);
988 break;
989
990 case L2CEVT_L2CA_DATA_WRITE: /* Upper layer data to send */
991 l2c_enqueue_peer_data (p_ccb, (BT_HDR *)p_data);
992 l2c_link_check_send_pkts (p_ccb->p_lcb, NULL, NULL);
993 break;
994
995 case L2CEVT_L2CA_CONFIG_REQ: /* Upper layer config req */
996 p_ccb->chnl_state = CST_CONFIG;
997 p_ccb->config_done &= ~CFG_DONE_MASK;
998 l2cu_process_our_cfg_req (p_ccb, (tL2CAP_CFG_INFO *)p_data);
999 l2cu_send_peer_config_req (p_ccb, (tL2CAP_CFG_INFO *)p_data);
1000 btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_L2CAP_CHNL, L2CAP_CHNL_CFG_TIMEOUT);
1001 break;
1002
1003 case L2CEVT_TIMEOUT:
1004 /* Process the monitor/retransmission time-outs in flow control/retrans mode */
1005 if (p_ccb->peer_cfg.fcr.mode == L2CAP_FCR_ERTM_MODE) {
1006 l2c_fcr_proc_tout (p_ccb);
1007 }
1008 break;
1009
1010 case L2CEVT_ACK_TIMEOUT:
1011 l2c_fcr_proc_ack_tout (p_ccb);
1012 break;
1013 }
1014 }
1015
1016
1017 /*******************************************************************************
1018 **
1019 ** Function l2c_csm_w4_l2cap_disconnect_rsp
1020 **
1021 ** Description This function handles events when the channel is in
1022 ** CST_W4_L2CAP_DISCONNECT_RSP state.
1023 **
1024 ** Returns void
1025 **
1026 *******************************************************************************/
l2c_csm_w4_l2cap_disconnect_rsp(tL2C_CCB * p_ccb,UINT16 event,void * p_data)1027 static void l2c_csm_w4_l2cap_disconnect_rsp (tL2C_CCB *p_ccb, UINT16 event, void *p_data)
1028 {
1029 tL2CA_DISCONNECT_CFM_CB *disconnect_cfm = p_ccb->p_rcb->api.pL2CA_DisconnectCfm_Cb;
1030 UINT16 local_cid = p_ccb->local_cid;
1031
1032 #if (BT_TRACE_VERBOSE == TRUE)
1033 L2CAP_TRACE_EVENT ("L2CAP - LCID: 0x%04x st: W4_L2CAP_DISC_RSP evt: %s", p_ccb->local_cid, l2c_csm_get_event_name (event));
1034 #else
1035 L2CAP_TRACE_EVENT ("L2CAP - st: W4_L2CAP_DISC_RSP evt: %d", event);
1036 #endif
1037
1038 switch (event) {
1039 case L2CEVT_L2CAP_DISCONNECT_RSP: /* Peer disconnect response */
1040 l2cu_release_ccb (p_ccb);
1041 if (disconnect_cfm) {
1042 L2CAP_TRACE_API ("L2CAP - Calling DisconnectCfm_Cb(), CID: 0x%04x", local_cid);
1043 (*disconnect_cfm)(local_cid, L2CAP_DISC_OK);
1044 }
1045 break;
1046
1047 case L2CEVT_L2CAP_DISCONNECT_REQ: /* Peer disconnect request */
1048 l2cu_send_peer_disc_rsp (p_ccb->p_lcb, p_ccb->remote_id, p_ccb->local_cid, p_ccb->remote_cid);
1049 l2cu_release_ccb (p_ccb);
1050 if (disconnect_cfm) {
1051 L2CAP_TRACE_API ("L2CAP - Calling DisconnectCfm_Cb(), CID: 0x%04x", local_cid);
1052 (*disconnect_cfm)(local_cid, L2CAP_DISC_OK);
1053 }
1054 break;
1055
1056 case L2CEVT_LP_DISCONNECT_IND: /* Link was disconnected */
1057 case L2CEVT_TIMEOUT: /* Timeout */
1058 l2cu_release_ccb (p_ccb);
1059 if (disconnect_cfm) {
1060 L2CAP_TRACE_API ("L2CAP - Calling DisconnectCfm_Cb(), CID: 0x%04x", local_cid);
1061 (*disconnect_cfm)(local_cid, L2CAP_DISC_TIMEOUT);
1062 }
1063 break;
1064
1065 case L2CEVT_L2CAP_DATA: /* Peer data packet rcvd */
1066 case L2CEVT_L2CA_DATA_WRITE: /* Upper layer data to send */
1067 osi_free (p_data);
1068 break;
1069 }
1070 }
1071
1072
1073 /*******************************************************************************
1074 **
1075 ** Function l2c_csm_w4_l2ca_disconnect_rsp
1076 **
1077 ** Description This function handles events when the channel is in
1078 ** CST_W4_L2CA_DISCONNECT_RSP state.
1079 **
1080 ** Returns void
1081 **
1082 *******************************************************************************/
l2c_csm_w4_l2ca_disconnect_rsp(tL2C_CCB * p_ccb,UINT16 event,void * p_data)1083 static void l2c_csm_w4_l2ca_disconnect_rsp (tL2C_CCB *p_ccb, UINT16 event, void *p_data)
1084 {
1085 tL2CA_DISCONNECT_IND_CB *disconnect_ind = p_ccb->p_rcb->api.pL2CA_DisconnectInd_Cb;
1086 UINT16 local_cid = p_ccb->local_cid;
1087
1088 #if (BT_TRACE_VERBOSE == TRUE)
1089 L2CAP_TRACE_EVENT ("L2CAP - LCID: 0x%04x st: W4_L2CA_DISC_RSP evt: %s", p_ccb->local_cid, l2c_csm_get_event_name (event));
1090 #else
1091 L2CAP_TRACE_EVENT ("L2CAP - st: W4_L2CA_DISC_RSP evt: %d", event);
1092 #endif
1093
1094 switch (event) {
1095 case L2CEVT_LP_DISCONNECT_IND: /* Link was disconnected */
1096 L2CAP_TRACE_API ("L2CAP - Calling Disconnect_Ind_Cb(), CID: 0x%04x No Conf Needed", p_ccb->local_cid);
1097 l2cu_release_ccb (p_ccb);
1098 (*disconnect_ind)(local_cid, FALSE);
1099 break;
1100
1101 case L2CEVT_TIMEOUT:
1102 l2cu_send_peer_disc_rsp (p_ccb->p_lcb, p_ccb->remote_id, p_ccb->local_cid, p_ccb->remote_cid);
1103 L2CAP_TRACE_API ("L2CAP - Calling Disconnect_Ind_Cb(), CID: 0x%04x No Conf Needed", p_ccb->local_cid);
1104 l2cu_release_ccb (p_ccb);
1105 (*disconnect_ind)(local_cid, FALSE);
1106 break;
1107
1108 case L2CEVT_L2CA_DISCONNECT_REQ: /* Upper disconnect request */
1109 case L2CEVT_L2CA_DISCONNECT_RSP: /* Upper disconnect response */
1110 l2cu_send_peer_disc_rsp (p_ccb->p_lcb, p_ccb->remote_id, p_ccb->local_cid, p_ccb->remote_cid);
1111 l2cu_release_ccb (p_ccb);
1112 break;
1113
1114 case L2CEVT_L2CAP_DATA: /* Peer data packet rcvd */
1115 case L2CEVT_L2CA_DATA_WRITE: /* Upper layer data to send */
1116 osi_free (p_data);
1117 break;
1118 }
1119 }
1120 #endif ///CLASSIC_BT_INCLUDED == TRUE
1121
1122 #if (BT_TRACE_VERBOSE == TRUE)
1123 /*******************************************************************************
1124 **
1125 ** Function l2c_csm_get_event_name
1126 **
1127 ** Description This function returns the event name.
1128 **
1129 ** NOTE conditionally compiled to save memory.
1130 **
1131 ** Returns pointer to the name
1132 **
1133 *******************************************************************************/
l2c_csm_get_event_name(UINT16 event)1134 static char *l2c_csm_get_event_name (UINT16 event)
1135 {
1136 switch (event) {
1137 case L2CEVT_LP_CONNECT_CFM: /* Lower layer connect confirm */
1138 return ("LOWER_LAYER_CONNECT_CFM");
1139 case L2CEVT_LP_CONNECT_CFM_NEG: /* Lower layer connect confirm (failed) */
1140 return ("LOWER_LAYER_CONNECT_CFM_NEG");
1141 case L2CEVT_LP_CONNECT_IND: /* Lower layer connect indication */
1142 return ("LOWER_LAYER_CONNECT_IND");
1143 case L2CEVT_LP_DISCONNECT_IND: /* Lower layer disconnect indication */
1144 return ("LOWER_LAYER_DISCONNECT_IND");
1145 case L2CEVT_LP_QOS_CFM: /* Lower layer QOS confirmation */
1146 return ("LOWER_LAYER_QOS_CFM");
1147 case L2CEVT_LP_QOS_CFM_NEG: /* Lower layer QOS confirmation (failed)*/
1148 return ("LOWER_LAYER_QOS_CFM_NEG");
1149 case L2CEVT_LP_QOS_VIOLATION_IND: /* Lower layer QOS violation indication */
1150 return ("LOWER_LAYER_QOS_VIOLATION_IND");
1151
1152 case L2CEVT_SEC_COMP: /* Security cleared successfully */
1153 return ("SECURITY_COMPLETE");
1154 case L2CEVT_SEC_COMP_NEG: /* Security procedure failed */
1155 return ("SECURITY_COMPLETE_NEG");
1156
1157 case L2CEVT_L2CAP_CONNECT_REQ: /* Peer connection request */
1158 return ("PEER_CONNECT_REQ");
1159 case L2CEVT_L2CAP_CONNECT_RSP: /* Peer connection response */
1160 return ("PEER_CONNECT_RSP");
1161 case L2CEVT_L2CAP_CONNECT_RSP_PND: /* Peer connection response pending */
1162 return ("PEER_CONNECT_RSP_PND");
1163 case L2CEVT_L2CAP_CONNECT_RSP_NEG: /* Peer connection response (failed) */
1164 return ("PEER_CONNECT_RSP_NEG");
1165 case L2CEVT_L2CAP_CONFIG_REQ: /* Peer configuration request */
1166 return ("PEER_CONFIG_REQ");
1167 case L2CEVT_L2CAP_CONFIG_RSP: /* Peer configuration response */
1168 return ("PEER_CONFIG_RSP");
1169 case L2CEVT_L2CAP_CONFIG_RSP_NEG: /* Peer configuration response (failed) */
1170 return ("PEER_CONFIG_RSP_NEG");
1171 case L2CEVT_L2CAP_DISCONNECT_REQ: /* Peer disconnect request */
1172 return ("PEER_DISCONNECT_REQ");
1173 case L2CEVT_L2CAP_DISCONNECT_RSP: /* Peer disconnect response */
1174 return ("PEER_DISCONNECT_RSP");
1175 case L2CEVT_L2CAP_DATA: /* Peer data */
1176 return ("PEER_DATA");
1177
1178 case L2CEVT_L2CA_CONNECT_REQ: /* Upper layer connect request */
1179 return ("UPPER_LAYER_CONNECT_REQ");
1180 case L2CEVT_L2CA_CONNECT_RSP: /* Upper layer connect response */
1181 return ("UPPER_LAYER_CONNECT_RSP");
1182 case L2CEVT_L2CA_CONNECT_RSP_NEG: /* Upper layer connect response (failed)*/
1183 return ("UPPER_LAYER_CONNECT_RSP_NEG");
1184 case L2CEVT_L2CA_CONFIG_REQ: /* Upper layer config request */
1185 return ("UPPER_LAYER_CONFIG_REQ");
1186 case L2CEVT_L2CA_CONFIG_RSP: /* Upper layer config response */
1187 return ("UPPER_LAYER_CONFIG_RSP");
1188 case L2CEVT_L2CA_CONFIG_RSP_NEG: /* Upper layer config response (failed) */
1189 return ("UPPER_LAYER_CONFIG_RSP_NEG");
1190 case L2CEVT_L2CA_DISCONNECT_REQ: /* Upper layer disconnect request */
1191 return ("UPPER_LAYER_DISCONNECT_REQ");
1192 case L2CEVT_L2CA_DISCONNECT_RSP: /* Upper layer disconnect response */
1193 return ("UPPER_LAYER_DISCONNECT_RSP");
1194 case L2CEVT_L2CA_DATA_READ: /* Upper layer data read */
1195 return ("UPPER_LAYER_DATA_READ");
1196 case L2CEVT_L2CA_DATA_WRITE: /* Upper layer data write */
1197 return ("UPPER_LAYER_DATA_WRITE");
1198 case L2CEVT_TIMEOUT: /* Timeout */
1199 return ("TIMEOUT");
1200 case L2CEVT_SEC_RE_SEND_CMD:
1201 return ("SEC_RE_SEND_CMD");
1202 case L2CEVT_L2CAP_INFO_RSP: /* Peer information response */
1203 return ("L2CEVT_L2CAP_INFO_RSP");
1204 case L2CEVT_ACK_TIMEOUT:
1205 return ("L2CEVT_ACK_TIMEOUT");
1206
1207 default:
1208 return ("???? UNKNOWN EVENT");
1209 }
1210 }
1211 #endif /* (BT_TRACE_VERBOSE == TRUE) */
1212
1213
1214 /*******************************************************************************
1215 **
1216 ** Function l2c_enqueue_peer_data
1217 **
1218 ** Description Enqueues data destined for the peer in the ccb. Handles
1219 ** FCR segmentation and checks for congestion.
1220 **
1221 ** Returns void
1222 **
1223 *******************************************************************************/
l2c_enqueue_peer_data(tL2C_CCB * p_ccb,BT_HDR * p_buf)1224 void l2c_enqueue_peer_data (tL2C_CCB *p_ccb, BT_HDR *p_buf)
1225 {
1226 UINT8 *p;
1227
1228 if (p_ccb->peer_cfg.fcr.mode != L2CAP_FCR_BASIC_MODE) {
1229 p_buf->event = 0;
1230 } else {
1231 /* Save the channel ID for faster counting */
1232 p_buf->event = p_ccb->local_cid;
1233
1234 /* Step back to add the L2CAP header */
1235 p_buf->offset -= L2CAP_PKT_OVERHEAD;
1236 p_buf->len += L2CAP_PKT_OVERHEAD;
1237
1238 /* Set the pointer to the beginning of the data */
1239 p = (UINT8 *)(p_buf + 1) + p_buf->offset;
1240
1241 /* Now the L2CAP header */
1242 UINT16_TO_STREAM (p, p_buf->len - L2CAP_PKT_OVERHEAD);
1243 UINT16_TO_STREAM (p, p_ccb->remote_cid);
1244 }
1245
1246 fixed_queue_enqueue(p_ccb->xmit_hold_q, p_buf, FIXED_QUEUE_MAX_TIMEOUT);
1247
1248 l2cu_check_channel_congestion (p_ccb);
1249
1250 #if (L2CAP_ROUND_ROBIN_CHANNEL_SERVICE == TRUE)
1251 /* if new packet is higher priority than serving ccb and it is not overrun */
1252 if (( p_ccb->p_lcb->rr_pri > p_ccb->ccb_priority )
1253 && ( p_ccb->p_lcb->rr_serv[p_ccb->ccb_priority].quota > 0)) {
1254 /* send out higher priority packet */
1255 p_ccb->p_lcb->rr_pri = p_ccb->ccb_priority;
1256 }
1257 #endif
1258
1259 /* if we are doing a round robin scheduling, set the flag */
1260 if (p_ccb->p_lcb->link_xmit_quota == 0) {
1261 l2cb.check_round_robin = TRUE;
1262 }
1263 }
1264