1 /******************************************************************************
3 * Copyright (C) 1999-2012 Broadcom Corporation
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:
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 ******************************************************************************/
19 /******************************************************************************
21 * This file contains the L2CAP channel state machine
23 ******************************************************************************/
29 #include "bt_target.h"
30 #include "bt_common.h"
40 extern fixed_queue_t *btu_general_alarm_queue;
42 /********************************************************************************/
43 /* L O C A L F U N C T I O N P R O T O T Y P E S */
44 /********************************************************************************/
45 static void l2c_csm_closed (tL2C_CCB *p_ccb, UINT16 event, void *p_data);
46 static void l2c_csm_orig_w4_sec_comp (tL2C_CCB *p_ccb, UINT16 event, void *p_data);
47 static void l2c_csm_term_w4_sec_comp (tL2C_CCB *p_ccb, UINT16 event, void *p_data);
48 static void l2c_csm_w4_l2cap_connect_rsp (tL2C_CCB *p_ccb, UINT16 event, void *p_data);
49 static void l2c_csm_w4_l2ca_connect_rsp (tL2C_CCB *p_ccb, UINT16 event, void *p_data);
50 static void l2c_csm_config (tL2C_CCB *p_ccb, UINT16 event, void *p_data);
51 static void l2c_csm_open (tL2C_CCB *p_ccb, UINT16 event, void *p_data);
52 static void l2c_csm_w4_l2cap_disconnect_rsp (tL2C_CCB *p_ccb, UINT16 event, void *p_data);
53 static void l2c_csm_w4_l2ca_disconnect_rsp (tL2C_CCB *p_ccb, UINT16 event, void *p_data);
55 #if (BT_TRACE_VERBOSE == TRUE)
56 static char *l2c_csm_get_event_name (UINT16 event);
59 /*******************************************************************************
61 ** Function l2c_csm_execute
63 ** Description This function executes the state machine.
67 *******************************************************************************/
68 void l2c_csm_execute (tL2C_CCB *p_ccb, UINT16 event, void *p_data)
70 switch (p_ccb->chnl_state)
73 l2c_csm_closed (p_ccb, event, p_data);
76 case CST_ORIG_W4_SEC_COMP:
77 l2c_csm_orig_w4_sec_comp (p_ccb, event, p_data);
80 case CST_TERM_W4_SEC_COMP:
81 l2c_csm_term_w4_sec_comp (p_ccb, event, p_data);
84 case CST_W4_L2CAP_CONNECT_RSP:
85 l2c_csm_w4_l2cap_connect_rsp (p_ccb, event, p_data);
88 case CST_W4_L2CA_CONNECT_RSP:
89 l2c_csm_w4_l2ca_connect_rsp (p_ccb, event, p_data);
93 l2c_csm_config (p_ccb, event, p_data);
97 l2c_csm_open (p_ccb, event, p_data);
100 case CST_W4_L2CAP_DISCONNECT_RSP:
101 l2c_csm_w4_l2cap_disconnect_rsp (p_ccb, event, p_data);
104 case CST_W4_L2CA_DISCONNECT_RSP:
105 l2c_csm_w4_l2ca_disconnect_rsp (p_ccb, event, p_data);
109 L2CAP_TRACE_DEBUG("Unhandled event! event = %d",event);
114 /*******************************************************************************
116 ** Function l2c_csm_closed
118 ** Description This function handles events when the channel is in
119 ** CLOSED state. This state exists only when the link is
120 ** being initially established.
124 *******************************************************************************/
125 static void l2c_csm_closed (tL2C_CCB *p_ccb, UINT16 event, void *p_data)
127 tL2C_CONN_INFO *p_ci = (tL2C_CONN_INFO *)p_data;
128 UINT16 local_cid = p_ccb->local_cid;
129 tL2CA_DISCONNECT_IND_CB *disconnect_ind;
130 tL2CA_CONNECT_CFM_CB *connect_cfm;
132 if (p_ccb->p_rcb == NULL)
134 #if (BT_TRACE_VERBOSE == TRUE)
135 L2CAP_TRACE_ERROR ("L2CAP - LCID: 0x%04x st: CLOSED evt: %s p_rcb == NULL", p_ccb->local_cid, l2c_csm_get_event_name (event));
137 L2CAP_TRACE_ERROR ("L2CAP - LCID: 0x%04x st: CLOSED evt: 0x%04x p_rcb == NULL", p_ccb->local_cid, event);
142 #if (L2CAP_UCD_INCLUDED == TRUE)
143 if ( local_cid == L2CAP_CONNECTIONLESS_CID )
145 /* check if this event can be processed by UCD */
146 if ( l2c_ucd_process_event (p_ccb, event, p_data) )
148 /* The event is processed by UCD state machine */
154 disconnect_ind = p_ccb->p_rcb->api.pL2CA_DisconnectInd_Cb;
155 connect_cfm = p_ccb->p_rcb->api.pL2CA_ConnectCfm_Cb;
157 #if (BT_TRACE_VERBOSE == TRUE)
158 L2CAP_TRACE_EVENT ("L2CAP - LCID: 0x%04x st: CLOSED evt: %s", p_ccb->local_cid, l2c_csm_get_event_name (event));
160 L2CAP_TRACE_EVENT ("L2CAP - st: CLOSED evt: %d", event);
165 case L2CEVT_LP_DISCONNECT_IND: /* Link was disconnected */
166 L2CAP_TRACE_API ("L2CAP - Calling Disconnect_Ind_Cb(), CID: 0x%04x No Conf Needed", p_ccb->local_cid);
167 l2cu_release_ccb (p_ccb);
168 (*disconnect_ind)(local_cid, FALSE);
171 case L2CEVT_LP_CONNECT_CFM: /* Link came up */
172 if (p_ccb->p_lcb->transport == BT_TRANSPORT_LE)
174 p_ccb->chnl_state = CST_ORIG_W4_SEC_COMP;
175 l2ble_sec_access_req(p_ccb->p_lcb->remote_bd_addr, p_ccb->p_rcb->psm, TRUE,
176 &l2c_link_sec_comp, p_ccb);
180 p_ccb->chnl_state = CST_ORIG_W4_SEC_COMP;
181 btm_sec_l2cap_access_req (p_ccb->p_lcb->remote_bd_addr, p_ccb->p_rcb->psm,
182 p_ccb->p_lcb->handle, TRUE, &l2c_link_sec_comp, p_ccb);
186 case L2CEVT_LP_CONNECT_CFM_NEG: /* Link failed */
187 /* Disconnect unless ACL collision and upper layer wants to handle it */
188 if (p_ci->status != HCI_ERR_CONNECTION_EXISTS
189 || !btm_acl_notif_conn_collision(p_ccb->p_lcb->remote_bd_addr))
191 L2CAP_TRACE_API ("L2CAP - Calling ConnectCfm_Cb(), CID: 0x%04x Status: %d", p_ccb->local_cid, p_ci->status);
192 l2cu_release_ccb (p_ccb);
193 (*connect_cfm)(local_cid, p_ci->status);
197 case L2CEVT_L2CA_CONNECT_REQ: /* API connect request */
198 if (p_ccb->p_lcb->transport == BT_TRANSPORT_LE)
200 p_ccb->chnl_state = CST_ORIG_W4_SEC_COMP;
201 l2ble_sec_access_req(p_ccb->p_lcb->remote_bd_addr, p_ccb->p_rcb->psm, TRUE,
202 &l2c_link_sec_comp, p_ccb);
206 /* Cancel sniff mode if needed */
208 tBTM_PM_PWR_MD settings;
209 memset((void*)&settings, 0, sizeof(settings));
210 settings.mode = BTM_PM_MD_ACTIVE;
212 Event uninit_use_in_call: Using uninitialized value "settings" (field "settings".timeout uninitialized) in call to function "BTM_SetPowerMode" [details]
213 Event uninit_use_in_call: Using uninitialized value "settings.max" in call to function "BTM_SetPowerMode" [details]
214 Event uninit_use_in_call: Using uninitialized value "settings.min" in call to function "BTM_SetPowerMode"
215 // FALSE-POSITIVE error from Coverity test-tool. Please do NOT remove following comment.
216 // 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
218 BTM_SetPowerMode (BTM_PM_SET_ONLY_ID, p_ccb->p_lcb->remote_bd_addr, &settings);
221 /* If sec access does not result in started SEC_COM or COMP_NEG are already processed */
222 if (btm_sec_l2cap_access_req (p_ccb->p_lcb->remote_bd_addr, p_ccb->p_rcb->psm,
223 p_ccb->p_lcb->handle, TRUE, &l2c_link_sec_comp, p_ccb) == BTM_CMD_STARTED)
224 p_ccb->chnl_state = CST_ORIG_W4_SEC_COMP;
228 case L2CEVT_SEC_COMP:
229 p_ccb->chnl_state = CST_W4_L2CAP_CONNECT_RSP;
231 /* Wait for the info resp in this state before sending connect req (if needed) */
232 if (!p_ccb->p_lcb->w4_info_rsp)
234 /* Need to have at least one compatible channel to continue */
235 if (!l2c_fcr_chk_chan_modes(p_ccb))
237 l2cu_release_ccb (p_ccb);
238 (*p_ccb->p_rcb->api.pL2CA_ConnectCfm_Cb)(local_cid, L2CAP_CONN_NO_LINK);
242 l2cu_send_peer_connect_req (p_ccb);
243 alarm_set_on_queue(p_ccb->l2c_ccb_timer,
244 L2CAP_CHNL_CONNECT_TIMEOUT_MS,
245 l2c_ccb_timer_timeout, p_ccb,
246 btu_general_alarm_queue);
251 case L2CEVT_SEC_COMP_NEG: /* something is really bad with security */
252 L2CAP_TRACE_API ("L2CAP - Calling ConnectCfm_Cb(), CID: 0x%04x Status: %d", p_ccb->local_cid, L2CAP_CONN_TIMEOUT);
253 l2cu_release_ccb (p_ccb);
254 (*connect_cfm)(local_cid, L2CAP_CONN_SECURITY_BLOCK);
257 case L2CEVT_L2CAP_CONNECT_REQ: /* Peer connect request */
258 /* stop link timer to avoid race condition between A2MP, Security, and L2CAP */
259 alarm_cancel(p_ccb->p_lcb->l2c_lcb_timer);
261 if (p_ccb->p_lcb->transport == BT_TRANSPORT_LE)
263 p_ccb->chnl_state = CST_TERM_W4_SEC_COMP;
264 l2ble_sec_access_req(p_ccb->p_lcb->remote_bd_addr, p_ccb->p_rcb->psm, FALSE,
265 &l2c_link_sec_comp, p_ccb);
269 /* Cancel sniff mode if needed */
271 tBTM_PM_PWR_MD settings;
272 memset((void*)&settings, 0, sizeof(settings));
273 settings.mode = BTM_PM_MD_ACTIVE;
275 Event uninit_use_in_call: Using uninitialized value "settings" (field "settings".timeout uninitialized) in call to function "BTM_SetPowerMode" [details]
276 Event uninit_use_in_call: Using uninitialized value "settings.max" in call to function "BTM_SetPowerMode" [details]
277 Event uninit_use_in_call: Using uninitialized value "settings.min" in call to function "BTM_SetPowerMode"
278 // FALSE-POSITIVE error from Coverity test-tool. Please do NOT remove following comment.
279 // 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
281 BTM_SetPowerMode (BTM_PM_SET_ONLY_ID, p_ccb->p_lcb->remote_bd_addr, &settings);
284 p_ccb->chnl_state = CST_TERM_W4_SEC_COMP;
285 if (btm_sec_l2cap_access_req (p_ccb->p_lcb->remote_bd_addr, p_ccb->p_rcb->psm,
286 p_ccb->p_lcb->handle, FALSE, &l2c_link_sec_comp, p_ccb) == BTM_CMD_STARTED)
288 /* started the security process, tell the peer to set a longer timer */
289 l2cu_send_peer_connect_rsp(p_ccb, L2CAP_CONN_PENDING, 0);
295 L2CAP_TRACE_API ("L2CAP - Calling ConnectCfm_Cb(), CID: 0x%04x Status: %d", p_ccb->local_cid, L2CAP_CONN_TIMEOUT);
296 l2cu_release_ccb (p_ccb);
297 (*connect_cfm)(local_cid, L2CAP_CONN_TIMEOUT);
300 case L2CEVT_L2CAP_DATA: /* Peer data packet rcvd */
301 case L2CEVT_L2CA_DATA_WRITE: /* Upper layer data to send */
305 case L2CEVT_L2CA_DISCONNECT_REQ: /* Upper wants to disconnect */
306 l2cu_release_ccb (p_ccb);
309 case L2CEVT_L2CA_SEND_FLOW_CONTROL_CREDIT:
310 case L2CEVT_L2CAP_RECV_FLOW_CONTROL_CREDIT:
317 /*******************************************************************************
319 ** Function l2c_csm_orig_w4_sec_comp
321 ** Description This function handles events when the channel is in
322 ** CST_ORIG_W4_SEC_COMP state.
326 *******************************************************************************/
327 static void l2c_csm_orig_w4_sec_comp (tL2C_CCB *p_ccb, UINT16 event, void *p_data)
329 tL2CA_DISCONNECT_IND_CB *disconnect_ind = p_ccb->p_rcb->api.pL2CA_DisconnectInd_Cb;
330 tL2CA_CONNECT_CFM_CB *connect_cfm = p_ccb->p_rcb->api.pL2CA_ConnectCfm_Cb;
331 UINT16 local_cid = p_ccb->local_cid;
333 #if (BT_TRACE_VERBOSE == TRUE)
334 L2CAP_TRACE_EVENT ("L2CAP - LCID: 0x%04x st: ORIG_W4_SEC_COMP evt: %s", p_ccb->local_cid, l2c_csm_get_event_name (event));
336 L2CAP_TRACE_EVENT ("L2CAP - st: ORIG_W4_SEC_COMP evt: %d", event);
339 #if (L2CAP_UCD_INCLUDED == TRUE)
340 if ( local_cid == L2CAP_CONNECTIONLESS_CID )
342 /* check if this event can be processed by UCD */
343 if ( l2c_ucd_process_event (p_ccb, event, p_data) )
345 /* The event is processed by UCD state machine */
353 case L2CEVT_LP_DISCONNECT_IND: /* Link was disconnected */
354 L2CAP_TRACE_API ("L2CAP - Calling Disconnect_Ind_Cb(), CID: 0x%04x No Conf Needed", p_ccb->local_cid);
355 l2cu_release_ccb (p_ccb);
356 (*disconnect_ind)(local_cid, FALSE);
359 case L2CEVT_SEC_RE_SEND_CMD: /* BTM has enough info to proceed */
360 case L2CEVT_LP_CONNECT_CFM: /* Link came up */
361 if (p_ccb->p_lcb->transport == BT_TRANSPORT_LE)
363 l2ble_sec_access_req(p_ccb->p_lcb->remote_bd_addr, p_ccb->p_rcb->psm, FALSE,
364 &l2c_link_sec_comp, p_ccb);
368 btm_sec_l2cap_access_req (p_ccb->p_lcb->remote_bd_addr, p_ccb->p_rcb->psm,
369 p_ccb->p_lcb->handle, TRUE, &l2c_link_sec_comp, p_ccb);
373 case L2CEVT_SEC_COMP: /* Security completed success */
374 /* Wait for the info resp in this state before sending connect req (if needed) */
375 p_ccb->chnl_state = CST_W4_L2CAP_CONNECT_RSP;
376 if (p_ccb->p_lcb->transport == BT_TRANSPORT_LE)
378 alarm_set_on_queue(p_ccb->l2c_ccb_timer,
379 L2CAP_CHNL_CONNECT_TIMEOUT_MS,
380 l2c_ccb_timer_timeout, p_ccb,
381 btu_general_alarm_queue);
382 l2cble_credit_based_conn_req (p_ccb); /* Start Connection */
386 if (!p_ccb->p_lcb->w4_info_rsp)
388 /* Need to have at least one compatible channel to continue */
389 if (!l2c_fcr_chk_chan_modes(p_ccb))
391 l2cu_release_ccb (p_ccb);
392 (*connect_cfm)(local_cid, L2CAP_CONN_NO_LINK);
396 alarm_set_on_queue(p_ccb->l2c_ccb_timer,
397 L2CAP_CHNL_CONNECT_TIMEOUT_MS,
398 l2c_ccb_timer_timeout, p_ccb,
399 btu_general_alarm_queue);
400 l2cu_send_peer_connect_req (p_ccb); /* Start Connection */
406 case L2CEVT_SEC_COMP_NEG:
407 L2CAP_TRACE_API ("L2CAP - Calling ConnectCfm_Cb(), CID: 0x%04x Status: %d", p_ccb->local_cid, HCI_ERR_AUTH_FAILURE);
409 /* If last channel immediately disconnect the ACL for better security.
410 Also prevents a race condition between BTM and L2CAP */
411 if ( (p_ccb == p_ccb->p_lcb->ccb_queue.p_first_ccb) && (p_ccb == p_ccb->p_lcb->ccb_queue.p_last_ccb) )
413 p_ccb->p_lcb->idle_timeout = 0;
416 l2cu_release_ccb (p_ccb);
417 (*connect_cfm)(local_cid, HCI_ERR_AUTH_FAILURE);
420 case L2CEVT_L2CA_DATA_WRITE: /* Upper layer data to send */
421 case L2CEVT_L2CAP_DATA: /* Peer data packet rcvd */
425 case L2CEVT_L2CA_DISCONNECT_REQ: /* Upper wants to disconnect */
426 /* Tell security manager to abort */
427 btm_sec_abort_access_req (p_ccb->p_lcb->remote_bd_addr);
429 l2cu_release_ccb (p_ccb);
435 /*******************************************************************************
437 ** Function l2c_csm_term_w4_sec_comp
439 ** Description This function handles events when the channel is in
440 ** CST_TERM_W4_SEC_COMP state.
444 *******************************************************************************/
445 static void l2c_csm_term_w4_sec_comp (tL2C_CCB *p_ccb, UINT16 event, void *p_data)
447 #if (BT_TRACE_VERBOSE == TRUE)
448 L2CAP_TRACE_EVENT ("L2CAP - LCID: 0x%04x st: TERM_W4_SEC_COMP evt: %s", p_ccb->local_cid, l2c_csm_get_event_name (event));
450 L2CAP_TRACE_EVENT ("L2CAP - st: TERM_W4_SEC_COMP evt: %d", event);
453 #if (L2CAP_UCD_INCLUDED == TRUE)
454 if ( p_ccb->local_cid == L2CAP_CONNECTIONLESS_CID )
456 /* check if this event can be processed by UCD */
457 if ( l2c_ucd_process_event (p_ccb, event, p_data) )
459 /* The event is processed by UCD state machine */
467 case L2CEVT_LP_DISCONNECT_IND: /* Link was disconnected */
468 /* Tell security manager to abort */
469 btm_sec_abort_access_req (p_ccb->p_lcb->remote_bd_addr);
471 l2cu_release_ccb (p_ccb);
474 case L2CEVT_SEC_COMP:
475 p_ccb->chnl_state = CST_W4_L2CA_CONNECT_RSP;
477 /* Wait for the info resp in next state before sending connect ind (if needed) */
478 if (!p_ccb->p_lcb->w4_info_rsp)
480 /* Don't need to get info from peer or already retrieved so continue */
481 alarm_set_on_queue(p_ccb->l2c_ccb_timer,
482 L2CAP_CHNL_CONNECT_TIMEOUT_MS,
483 l2c_ccb_timer_timeout, p_ccb,
484 btu_general_alarm_queue);
485 L2CAP_TRACE_API ("L2CAP - Calling Connect_Ind_Cb(), CID: 0x%04x", p_ccb->local_cid);
487 (*p_ccb->p_rcb->api.pL2CA_ConnectInd_Cb) (p_ccb->p_lcb->remote_bd_addr, p_ccb->local_cid,
488 p_ccb->p_rcb->psm, p_ccb->remote_id);
493 ** L2CAP Connect Response will be sent out by 3 sec timer expiration
494 ** because Bluesoleil doesn't respond to L2CAP Information Request.
495 ** Bluesoleil seems to disconnect ACL link as failure case, because
496 ** it takes too long (4~7secs) to get response.
497 ** product version : Bluesoleil 2.1.1.0 EDR Release 060123
498 ** stack version : 05.04.11.20060119
501 /* Waiting for the info resp, tell the peer to set a longer timer */
502 l2cu_send_peer_connect_rsp(p_ccb, L2CAP_CONN_PENDING, 0);
506 case L2CEVT_SEC_COMP_NEG:
507 if (((tL2C_CONN_INFO *)p_data)->status == BTM_DELAY_CHECK)
509 /* start a timer - encryption change not received before L2CAP connect req */
510 alarm_set_on_queue(p_ccb->l2c_ccb_timer,
511 L2CAP_DELAY_CHECK_SM4_TIMEOUT_MS,
512 l2c_ccb_timer_timeout, p_ccb,
513 btu_general_alarm_queue);
517 if (p_ccb->p_lcb->transport == BT_TRANSPORT_LE)
518 l2cu_reject_ble_connection(p_ccb->p_lcb, p_ccb->remote_id, L2CAP_LE_INSUFFICIENT_AUTHENTICATION);
520 l2cu_send_peer_connect_rsp (p_ccb, L2CAP_CONN_SECURITY_BLOCK, 0);
521 l2cu_release_ccb (p_ccb);
525 case L2CEVT_L2CA_DATA_WRITE: /* Upper layer data to send */
526 case L2CEVT_L2CAP_DATA: /* Peer data packet rcvd */
530 case L2CEVT_L2CA_DISCONNECT_REQ: /* Upper wants to disconnect */
531 l2cu_release_ccb (p_ccb);
534 case L2CEVT_L2CAP_DISCONNECT_REQ: /* Peer disconnected request */
535 l2cu_send_peer_disc_rsp (p_ccb->p_lcb, p_ccb->remote_id, p_ccb->local_cid, p_ccb->remote_cid);
537 /* Tell security manager to abort */
538 btm_sec_abort_access_req (p_ccb->p_lcb->remote_bd_addr);
540 l2cu_release_ccb (p_ccb);
545 if (!btsnd_hcic_disconnect (p_ccb->p_lcb->handle, HCI_ERR_AUTH_FAILURE))
547 L2CAP_TRACE_API ("L2CAP - Calling btsnd_hcic_disconnect for handle %i failed", p_ccb->p_lcb->handle);
548 alarm_set_on_queue(p_ccb->l2c_ccb_timer, BT_1SEC_TIMEOUT_MS,
549 l2c_ccb_timer_timeout, p_ccb,
550 btu_general_alarm_queue);
554 case L2CEVT_SEC_RE_SEND_CMD: /* BTM has enough info to proceed */
555 btm_sec_l2cap_access_req (p_ccb->p_lcb->remote_bd_addr, p_ccb->p_rcb->psm,
556 p_ccb->p_lcb->handle, FALSE, &l2c_link_sec_comp, p_ccb);
562 /*******************************************************************************
564 ** Function l2c_csm_w4_l2cap_connect_rsp
566 ** Description This function handles events when the channel is in
567 ** CST_W4_L2CAP_CONNECT_RSP state.
571 *******************************************************************************/
572 static void l2c_csm_w4_l2cap_connect_rsp (tL2C_CCB *p_ccb, UINT16 event, void *p_data)
574 tL2C_CONN_INFO *p_ci = (tL2C_CONN_INFO *)p_data;
575 tL2CA_DISCONNECT_IND_CB *disconnect_ind = p_ccb->p_rcb->api.pL2CA_DisconnectInd_Cb;
576 tL2CA_CONNECT_CFM_CB *connect_cfm = p_ccb->p_rcb->api.pL2CA_ConnectCfm_Cb;
577 UINT16 local_cid = p_ccb->local_cid;
579 #if (BT_TRACE_VERBOSE == TRUE)
580 L2CAP_TRACE_EVENT ("L2CAP - LCID: 0x%04x st: W4_L2CAP_CON_RSP evt: %s", p_ccb->local_cid, l2c_csm_get_event_name (event));
582 L2CAP_TRACE_EVENT ("L2CAP - st: W4_L2CAP_CON_RSP evt: %d", event);
587 case L2CEVT_LP_DISCONNECT_IND: /* Link was disconnected */
588 /* Send disc indication unless peer to peer race condition AND normal disconnect */
589 /* *((UINT8 *)p_data) != HCI_ERR_PEER_USER happens when peer device try to disconnect for normal reason */
590 p_ccb->chnl_state = CST_CLOSED;
591 if ((p_ccb->flags & CCB_FLAG_NO_RETRY) || !p_data || (*((UINT8 *)p_data) != HCI_ERR_PEER_USER))
593 L2CAP_TRACE_API ("L2CAP - Calling Disconnect_Ind_Cb(), CID: 0x%04x No Conf Needed",
595 l2cu_release_ccb (p_ccb);
596 (*disconnect_ind)(local_cid, FALSE);
598 p_ccb->flags |= CCB_FLAG_NO_RETRY;
601 case L2CEVT_L2CAP_CONNECT_RSP: /* Got peer connect confirm */
602 p_ccb->remote_cid = p_ci->remote_cid;
603 if (p_ccb->p_lcb->transport == BT_TRANSPORT_LE)
605 /* Connection is completed */
606 alarm_cancel(p_ccb->l2c_ccb_timer);
607 p_ccb->chnl_state = CST_OPEN;
611 p_ccb->chnl_state = CST_CONFIG;
612 alarm_set_on_queue(p_ccb->l2c_ccb_timer, L2CAP_CHNL_CFG_TIMEOUT_MS,
613 l2c_ccb_timer_timeout, p_ccb,
614 btu_general_alarm_queue);
616 L2CAP_TRACE_API ("L2CAP - Calling Connect_Cfm_Cb(), CID: 0x%04x, Success", p_ccb->local_cid);
618 (*p_ccb->p_rcb->api.pL2CA_ConnectCfm_Cb)(local_cid, L2CAP_CONN_OK);
621 case L2CEVT_L2CAP_CONNECT_RSP_PND: /* Got peer connect pending */
622 p_ccb->remote_cid = p_ci->remote_cid;
623 alarm_set_on_queue(p_ccb->l2c_ccb_timer,
624 L2CAP_CHNL_CONNECT_EXT_TIMEOUT_MS,
625 l2c_ccb_timer_timeout, p_ccb,
626 btu_general_alarm_queue);
627 if (p_ccb->p_rcb->api.pL2CA_ConnectPnd_Cb)
629 L2CAP_TRACE_API ("L2CAP - Calling Connect_Pnd_Cb(), CID: 0x%04x", p_ccb->local_cid);
630 (*p_ccb->p_rcb->api.pL2CA_ConnectPnd_Cb)(p_ccb->local_cid);
634 case L2CEVT_L2CAP_CONNECT_RSP_NEG: /* Peer rejected connection */
635 L2CAP_TRACE_API ("L2CAP - Calling Connect_Cfm_Cb(), CID: 0x%04x, Failure Code: %d", p_ccb->local_cid, p_ci->l2cap_result);
636 l2cu_release_ccb (p_ccb);
637 (*connect_cfm)(local_cid, p_ci->l2cap_result);
641 L2CAP_TRACE_API ("L2CAP - Calling Connect_Cfm_Cb(), CID: 0x%04x, Timeout", p_ccb->local_cid);
642 l2cu_release_ccb (p_ccb);
643 (*connect_cfm)(local_cid, L2CAP_CONN_TIMEOUT);
646 case L2CEVT_L2CA_DISCONNECT_REQ: /* Upper wants to disconnect */
647 /* If we know peer CID from connect pending, we can send disconnect */
648 if (p_ccb->remote_cid != 0)
650 l2cu_send_peer_disc_req (p_ccb);
651 p_ccb->chnl_state = CST_W4_L2CAP_DISCONNECT_RSP;
652 alarm_set_on_queue(p_ccb->l2c_ccb_timer,
653 L2CAP_CHNL_DISCONNECT_TIMEOUT_MS,
654 l2c_ccb_timer_timeout, p_ccb,
655 btu_general_alarm_queue);
658 l2cu_release_ccb (p_ccb);
661 case L2CEVT_L2CA_DATA_WRITE: /* Upper layer data to send */
662 case L2CEVT_L2CAP_DATA: /* Peer data packet rcvd */
666 case L2CEVT_L2CAP_INFO_RSP:
667 /* Need to have at least one compatible channel to continue */
668 if (!l2c_fcr_chk_chan_modes(p_ccb))
670 l2cu_release_ccb (p_ccb);
671 (*connect_cfm)(local_cid, L2CAP_CONN_NO_LINK);
675 /* We have feature info, so now send peer connect request */
676 alarm_set_on_queue(p_ccb->l2c_ccb_timer,
677 L2CAP_CHNL_CONNECT_TIMEOUT_MS,
678 l2c_ccb_timer_timeout, p_ccb,
679 btu_general_alarm_queue);
680 l2cu_send_peer_connect_req (p_ccb); /* Start Connection */
684 case L2CEVT_L2CA_SEND_FLOW_CONTROL_CREDIT:
685 case L2CEVT_L2CAP_RECV_FLOW_CONTROL_CREDIT:
692 /*******************************************************************************
694 ** Function l2c_csm_w4_l2ca_connect_rsp
696 ** Description This function handles events when the channel is in
697 ** CST_W4_L2CA_CONNECT_RSP state.
701 *******************************************************************************/
702 static void l2c_csm_w4_l2ca_connect_rsp (tL2C_CCB *p_ccb, UINT16 event, void *p_data)
704 tL2C_CONN_INFO *p_ci;
705 tL2CA_DISCONNECT_IND_CB *disconnect_ind = p_ccb->p_rcb->api.pL2CA_DisconnectInd_Cb;
706 UINT16 local_cid = p_ccb->local_cid;
708 #if (BT_TRACE_VERBOSE == TRUE)
709 L2CAP_TRACE_EVENT ("L2CAP - LCID: 0x%04x st: W4_L2CA_CON_RSP evt: %s", p_ccb->local_cid, l2c_csm_get_event_name (event));
711 L2CAP_TRACE_EVENT ("L2CAP - st: W4_L2CA_CON_RSP evt: %d", event);
716 case L2CEVT_LP_DISCONNECT_IND: /* Link was disconnected */
717 L2CAP_TRACE_API ("L2CAP - Calling Disconnect_Ind_Cb(), CID: 0x%04x No Conf Needed", p_ccb->local_cid);
718 l2cu_release_ccb (p_ccb);
719 (*disconnect_ind)(local_cid, FALSE);
722 case L2CEVT_L2CA_CONNECT_RSP:
723 p_ci = (tL2C_CONN_INFO *)p_data;
724 if (p_ccb->p_lcb->transport == BT_TRANSPORT_LE)
726 /* Result should be OK or Reject */
727 if ((!p_ci) || (p_ci->l2cap_result == L2CAP_CONN_OK))
729 l2cble_credit_based_conn_res (p_ccb, L2CAP_CONN_OK);
730 p_ccb->chnl_state = CST_OPEN;
731 alarm_cancel(p_ccb->l2c_ccb_timer);
735 l2cble_credit_based_conn_res (p_ccb, p_ci->l2cap_result);
736 l2cu_release_ccb (p_ccb);
741 /* Result should be OK or PENDING */
742 if ((!p_ci) || (p_ci->l2cap_result == L2CAP_CONN_OK))
744 l2cu_send_peer_connect_rsp (p_ccb, L2CAP_CONN_OK, 0);
745 p_ccb->chnl_state = CST_CONFIG;
746 alarm_set_on_queue(p_ccb->l2c_ccb_timer,
747 L2CAP_CHNL_CFG_TIMEOUT_MS,
748 l2c_ccb_timer_timeout, p_ccb,
749 btu_general_alarm_queue);
753 /* If pending, stay in same state and start extended timer */
754 l2cu_send_peer_connect_rsp (p_ccb, p_ci->l2cap_result, p_ci->l2cap_status);
755 alarm_set_on_queue(p_ccb->l2c_ccb_timer,
756 L2CAP_CHNL_CONNECT_EXT_TIMEOUT_MS,
757 l2c_ccb_timer_timeout, p_ccb,
758 btu_general_alarm_queue);
763 case L2CEVT_L2CA_CONNECT_RSP_NEG:
764 p_ci = (tL2C_CONN_INFO *)p_data;
765 if (p_ccb->p_lcb->transport == BT_TRANSPORT_LE)
766 l2cble_credit_based_conn_res (p_ccb, p_ci->l2cap_result);
768 l2cu_send_peer_connect_rsp (p_ccb, p_ci->l2cap_result, p_ci->l2cap_status);
769 l2cu_release_ccb (p_ccb);
773 l2cu_send_peer_connect_rsp (p_ccb, L2CAP_CONN_NO_PSM, 0);
774 L2CAP_TRACE_API ("L2CAP - Calling Disconnect_Ind_Cb(), CID: 0x%04x No Conf Needed", p_ccb->local_cid);
775 l2cu_release_ccb (p_ccb);
776 (*disconnect_ind)(local_cid, FALSE);
779 case L2CEVT_L2CA_DATA_WRITE: /* Upper layer data to send */
780 case L2CEVT_L2CAP_DATA: /* Peer data packet rcvd */
784 case L2CEVT_L2CA_DISCONNECT_REQ: /* Upper wants to disconnect */
785 l2cu_send_peer_disc_req (p_ccb);
786 p_ccb->chnl_state = CST_W4_L2CAP_DISCONNECT_RSP;
787 alarm_set_on_queue(p_ccb->l2c_ccb_timer,
788 L2CAP_CHNL_DISCONNECT_TIMEOUT_MS,
789 l2c_ccb_timer_timeout, p_ccb,
790 btu_general_alarm_queue);
793 case L2CEVT_L2CAP_INFO_RSP:
794 /* We have feature info, so now give the upper layer connect IND */
795 alarm_set_on_queue(p_ccb->l2c_ccb_timer,
796 L2CAP_CHNL_CONNECT_TIMEOUT_MS,
797 l2c_ccb_timer_timeout, p_ccb,
798 btu_general_alarm_queue);
799 L2CAP_TRACE_API ("L2CAP - Calling Connect_Ind_Cb(), CID: 0x%04x", p_ccb->local_cid);
801 (*p_ccb->p_rcb->api.pL2CA_ConnectInd_Cb) (p_ccb->p_lcb->remote_bd_addr,
810 /*******************************************************************************
812 ** Function l2c_csm_config
814 ** Description This function handles events when the channel is in
819 *******************************************************************************/
820 static void l2c_csm_config (tL2C_CCB *p_ccb, UINT16 event, void *p_data)
822 tL2CAP_CFG_INFO *p_cfg = (tL2CAP_CFG_INFO *)p_data;
823 tL2CA_DISCONNECT_IND_CB *disconnect_ind = p_ccb->p_rcb->api.pL2CA_DisconnectInd_Cb;
824 UINT16 local_cid = p_ccb->local_cid;
827 #if (BT_TRACE_VERBOSE == TRUE)
828 L2CAP_TRACE_EVENT ("L2CAP - LCID: 0x%04x st: CONFIG evt: %s", p_ccb->local_cid, l2c_csm_get_event_name (event));
830 L2CAP_TRACE_EVENT ("L2CAP - st: CONFIG evt: %d", event);
835 case L2CEVT_LP_DISCONNECT_IND: /* Link was disconnected */
836 L2CAP_TRACE_API ("L2CAP - Calling Disconnect_Ind_Cb(), CID: 0x%04x No Conf Needed", p_ccb->local_cid);
837 l2cu_release_ccb (p_ccb);
838 (*disconnect_ind)(local_cid, FALSE);
841 case L2CEVT_L2CAP_CONFIG_REQ: /* Peer config request */
843 if ((cfg_result = l2cu_process_peer_cfg_req (p_ccb, p_cfg)) == L2CAP_PEER_CFG_OK)
845 L2CAP_TRACE_EVENT ("L2CAP - Calling Config_Req_Cb(), CID: 0x%04x, C-bit %d",
846 p_ccb->local_cid, (p_cfg->flags & L2CAP_CFG_FLAGS_MASK_CONT));
847 (*p_ccb->p_rcb->api.pL2CA_ConfigInd_Cb)(p_ccb->local_cid, p_cfg);
849 else if (cfg_result == L2CAP_PEER_CFG_DISCONNECT)
851 /* Disconnect if channels are incompatible */
852 L2CAP_TRACE_EVENT ("L2CAP - incompatible configurations disconnect");
853 l2cu_disconnect_chnl (p_ccb);
855 else /* Return error to peer so he can renegotiate if possible */
857 L2CAP_TRACE_EVENT ("L2CAP - incompatible configurations trying reconfig");
858 l2cu_send_peer_config_rsp (p_ccb, p_cfg);
862 case L2CEVT_L2CAP_CONFIG_RSP: /* Peer config response */
863 l2cu_process_peer_cfg_rsp (p_ccb, p_cfg);
865 if (p_cfg->result != L2CAP_CFG_PENDING)
867 /* TBD: When config options grow beyong minimum MTU (48 bytes)
868 * logic needs to be added to handle responses with
869 * continuation bit set in flags field.
870 * 1. Send additional config request out until C-bit is cleared in response
872 p_ccb->config_done |= OB_CFG_DONE;
874 if (p_ccb->config_done & IB_CFG_DONE)
876 /* Verify two sides are in compatible modes before continuing */
877 if (p_ccb->our_cfg.fcr.mode != p_ccb->peer_cfg.fcr.mode)
879 l2cu_send_peer_disc_req (p_ccb);
880 L2CAP_TRACE_WARNING ("L2CAP - Calling Disconnect_Ind_Cb(Incompatible CFG), CID: 0x%04x No Conf Needed", p_ccb->local_cid);
881 l2cu_release_ccb (p_ccb);
882 (*disconnect_ind)(local_cid, FALSE);
886 p_ccb->config_done |= RECONFIG_FLAG;
887 p_ccb->chnl_state = CST_OPEN;
888 l2c_link_adjust_chnl_allocation ();
889 alarm_cancel(p_ccb->l2c_ccb_timer);
891 /* If using eRTM and waiting for an ACK, restart the ACK timer */
892 if (p_ccb->fcrb.wait_ack)
893 l2c_fcr_start_timer(p_ccb);
896 ** check p_ccb->our_cfg.fcr.mon_tout and p_ccb->our_cfg.fcr.rtrans_tout
897 ** we may set them to zero when sending config request during renegotiation
899 if ((p_ccb->our_cfg.fcr.mode == L2CAP_FCR_ERTM_MODE)
900 &&((p_ccb->our_cfg.fcr.mon_tout == 0)||(p_ccb->our_cfg.fcr.rtrans_tout)))
902 l2c_fcr_adj_monitor_retran_timeout (p_ccb);
905 #if (L2CAP_ERTM_STATS == TRUE)
906 p_ccb->fcrb.connect_tick_count = time_get_os_boottime_ms();
908 /* See if we can forward anything on the hold queue */
909 if (!fixed_queue_is_empty(p_ccb->xmit_hold_q))
911 l2c_link_check_send_pkts (p_ccb->p_lcb, NULL, NULL);
916 L2CAP_TRACE_API ("L2CAP - Calling Config_Rsp_Cb(), CID: 0x%04x", p_ccb->local_cid);
917 (*p_ccb->p_rcb->api.pL2CA_ConfigCfm_Cb)(p_ccb->local_cid, p_cfg);
920 case L2CEVT_L2CAP_CONFIG_RSP_NEG: /* Peer config error rsp */
921 /* Disable the Timer */
922 alarm_cancel(p_ccb->l2c_ccb_timer);
924 /* If failure was channel mode try to renegotiate */
925 if (l2c_fcr_renegotiate_chan(p_ccb, p_cfg) == FALSE)
927 L2CAP_TRACE_API ("L2CAP - Calling Config_Rsp_Cb(), CID: 0x%04x, Failure: %d", p_ccb->local_cid, p_cfg->result);
928 (*p_ccb->p_rcb->api.pL2CA_ConfigCfm_Cb)(p_ccb->local_cid, p_cfg);
932 case L2CEVT_L2CAP_DISCONNECT_REQ: /* Peer disconnected request */
933 alarm_set_on_queue(p_ccb->l2c_ccb_timer,
934 L2CAP_CHNL_DISCONNECT_TIMEOUT_MS,
935 l2c_ccb_timer_timeout, p_ccb,
936 btu_general_alarm_queue);
937 p_ccb->chnl_state = CST_W4_L2CA_DISCONNECT_RSP;
938 L2CAP_TRACE_API ("L2CAP - Calling Disconnect_Ind_Cb(), CID: 0x%04x Conf Needed", p_ccb->local_cid);
939 (*p_ccb->p_rcb->api.pL2CA_DisconnectInd_Cb)(p_ccb->local_cid, TRUE);
942 case L2CEVT_L2CA_CONFIG_REQ: /* Upper layer config req */
943 l2cu_process_our_cfg_req (p_ccb, p_cfg);
944 l2cu_send_peer_config_req (p_ccb, p_cfg);
945 alarm_set_on_queue(p_ccb->l2c_ccb_timer,
946 L2CAP_CHNL_CFG_TIMEOUT_MS,
947 l2c_ccb_timer_timeout, p_ccb,
948 btu_general_alarm_queue);
951 case L2CEVT_L2CA_CONFIG_RSP: /* Upper layer config rsp */
952 l2cu_process_our_cfg_rsp (p_ccb, p_cfg);
954 /* Not finished if continuation flag is set */
955 if ( (p_cfg->flags & L2CAP_CFG_FLAGS_MASK_CONT) || (p_cfg->result == L2CAP_CFG_PENDING) )
957 /* Send intermediate response; remain in cfg state */
958 l2cu_send_peer_config_rsp (p_ccb, p_cfg);
962 /* Local config done; clear cached configuration in case reconfig takes place later */
963 p_ccb->peer_cfg.mtu_present = FALSE;
964 p_ccb->peer_cfg.flush_to_present = FALSE;
965 p_ccb->peer_cfg.qos_present = FALSE;
967 p_ccb->config_done |= IB_CFG_DONE;
969 if (p_ccb->config_done & OB_CFG_DONE)
971 /* Verify two sides are in compatible modes before continuing */
972 if (p_ccb->our_cfg.fcr.mode != p_ccb->peer_cfg.fcr.mode)
974 l2cu_send_peer_disc_req (p_ccb);
975 L2CAP_TRACE_WARNING ("L2CAP - Calling Disconnect_Ind_Cb(Incompatible CFG), CID: 0x%04x No Conf Needed", p_ccb->local_cid);
976 l2cu_release_ccb (p_ccb);
977 (*disconnect_ind)(local_cid, FALSE);
981 p_ccb->config_done |= RECONFIG_FLAG;
982 p_ccb->chnl_state = CST_OPEN;
983 l2c_link_adjust_chnl_allocation ();
984 alarm_cancel(p_ccb->l2c_ccb_timer);
987 l2cu_send_peer_config_rsp (p_ccb, p_cfg);
989 /* If using eRTM and waiting for an ACK, restart the ACK timer */
990 if (p_ccb->fcrb.wait_ack)
991 l2c_fcr_start_timer(p_ccb);
993 #if (L2CAP_ERTM_STATS == TRUE)
994 p_ccb->fcrb.connect_tick_count = time_get_os_boottime_ms();
997 /* See if we can forward anything on the hold queue */
998 if ( (p_ccb->chnl_state == CST_OPEN) &&
999 (!fixed_queue_is_empty(p_ccb->xmit_hold_q)))
1001 l2c_link_check_send_pkts (p_ccb->p_lcb, NULL, NULL);
1005 case L2CEVT_L2CA_CONFIG_RSP_NEG: /* Upper layer config reject */
1006 l2cu_send_peer_config_rsp (p_ccb, p_cfg);
1007 alarm_set_on_queue(p_ccb->l2c_ccb_timer,
1008 L2CAP_CHNL_CFG_TIMEOUT_MS,
1009 l2c_ccb_timer_timeout, p_ccb,
1010 btu_general_alarm_queue);
1013 case L2CEVT_L2CA_DISCONNECT_REQ: /* Upper wants to disconnect */
1014 l2cu_send_peer_disc_req (p_ccb);
1015 p_ccb->chnl_state = CST_W4_L2CAP_DISCONNECT_RSP;
1016 alarm_set_on_queue(p_ccb->l2c_ccb_timer,
1017 L2CAP_CHNL_DISCONNECT_TIMEOUT_MS,
1018 l2c_ccb_timer_timeout, p_ccb,
1019 btu_general_alarm_queue);
1022 case L2CEVT_L2CAP_DATA: /* Peer data packet rcvd */
1023 L2CAP_TRACE_API ("L2CAP - Calling DataInd_Cb(), CID: 0x%04x", p_ccb->local_cid);
1024 #if (L2CAP_NUM_FIXED_CHNLS > 0)
1025 if (p_ccb->local_cid >= L2CAP_FIRST_FIXED_CHNL &&
1026 p_ccb->local_cid <= L2CAP_LAST_FIXED_CHNL)
1028 if (p_ccb->local_cid < L2CAP_BASE_APPL_CID)
1030 if (l2cb.fixed_reg[p_ccb->local_cid - L2CAP_FIRST_FIXED_CHNL].pL2CA_FixedData_Cb)
1031 (*l2cb.fixed_reg[p_ccb->local_cid - L2CAP_FIRST_FIXED_CHNL].pL2CA_FixedData_Cb)
1032 (p_ccb->local_cid, p_ccb->p_lcb->remote_bd_addr,(BT_HDR *)p_data);
1039 (*p_ccb->p_rcb->api.pL2CA_DataInd_Cb)(p_ccb->local_cid, (BT_HDR *)p_data);
1042 case L2CEVT_L2CA_DATA_WRITE: /* Upper layer data to send */
1043 if (p_ccb->config_done & OB_CFG_DONE)
1044 l2c_enqueue_peer_data (p_ccb, (BT_HDR *)p_data);
1049 case L2CEVT_TIMEOUT:
1050 l2cu_send_peer_disc_req (p_ccb);
1051 L2CAP_TRACE_API ("L2CAP - Calling Disconnect_Ind_Cb(), CID: 0x%04x No Conf Needed",
1053 l2cu_release_ccb (p_ccb);
1054 (*disconnect_ind)(local_cid, FALSE);
1060 /*******************************************************************************
1062 ** Function l2c_csm_open
1064 ** Description This function handles events when the channel is in
1069 *******************************************************************************/
1070 static void l2c_csm_open (tL2C_CCB *p_ccb, UINT16 event, void *p_data)
1072 UINT16 local_cid = p_ccb->local_cid;
1073 tL2CAP_CFG_INFO *p_cfg;
1074 tL2C_CHNL_STATE tempstate;
1079 #if (BT_TRACE_VERBOSE == TRUE)
1080 L2CAP_TRACE_EVENT ("L2CAP - LCID: 0x%04x st: OPEN evt: %s",
1081 p_ccb->local_cid, l2c_csm_get_event_name (event));
1083 L2CAP_TRACE_EVENT ("L2CAP - st: OPEN evt: %d", event);
1086 #if (L2CAP_UCD_INCLUDED == TRUE)
1087 if ( local_cid == L2CAP_CONNECTIONLESS_CID )
1089 /* check if this event can be processed by UCD */
1090 if ( l2c_ucd_process_event (p_ccb, event, p_data) )
1092 /* The event is processed by UCD state machine */
1100 case L2CEVT_LP_DISCONNECT_IND: /* Link was disconnected */
1101 L2CAP_TRACE_API ("L2CAP - Calling Disconnect_Ind_Cb(), CID: 0x%04x No Conf Needed",
1103 l2cu_release_ccb (p_ccb);
1105 (*p_ccb->p_rcb->api.pL2CA_DisconnectInd_Cb)(local_cid, FALSE);
1108 case L2CEVT_LP_QOS_VIOLATION_IND: /* QOS violation */
1109 /* Tell upper layer. If service guaranteed, then clear the channel */
1110 if (p_ccb->p_rcb->api.pL2CA_QoSViolationInd_Cb)
1111 (*p_ccb->p_rcb->api.pL2CA_QoSViolationInd_Cb)(p_ccb->p_lcb->remote_bd_addr);
1114 case L2CEVT_L2CAP_CONFIG_REQ: /* Peer config request */
1115 p_cfg = (tL2CAP_CFG_INFO *)p_data;
1117 tempstate = p_ccb->chnl_state;
1118 tempcfgdone = p_ccb->config_done;
1119 p_ccb->chnl_state = CST_CONFIG;
1120 p_ccb->config_done &= ~CFG_DONE_MASK;
1122 alarm_set_on_queue(p_ccb->l2c_ccb_timer,
1123 L2CAP_CHNL_CFG_TIMEOUT_MS,
1124 l2c_ccb_timer_timeout, p_ccb,
1125 btu_general_alarm_queue);
1127 if ((cfg_result = l2cu_process_peer_cfg_req (p_ccb, p_cfg)) == L2CAP_PEER_CFG_OK)
1129 (*p_ccb->p_rcb->api.pL2CA_ConfigInd_Cb)(p_ccb->local_cid, p_cfg);
1132 /* Error in config parameters: reset state and config flag */
1133 else if (cfg_result == L2CAP_PEER_CFG_UNACCEPTABLE)
1135 alarm_cancel(p_ccb->l2c_ccb_timer);
1136 p_ccb->chnl_state = tempstate;
1137 p_ccb->config_done = tempcfgdone;
1138 l2cu_send_peer_config_rsp (p_ccb, p_cfg);
1140 else /* L2CAP_PEER_CFG_DISCONNECT */
1142 /* Disconnect if channels are incompatible
1143 * Note this should not occur if reconfigure
1144 * since this should have never passed original config.
1146 l2cu_disconnect_chnl (p_ccb);
1150 case L2CEVT_L2CAP_DISCONNECT_REQ: /* Peer disconnected request */
1151 if (p_ccb->p_lcb->transport != BT_TRANSPORT_LE)
1153 /* Make sure we are not in sniff mode */
1155 tBTM_PM_PWR_MD settings;
1156 memset((void*)&settings, 0, sizeof(settings));
1157 settings.mode = BTM_PM_MD_ACTIVE;
1158 BTM_SetPowerMode (BTM_PM_SET_ONLY_ID, p_ccb->p_lcb->remote_bd_addr, &settings);
1162 p_ccb->chnl_state = CST_W4_L2CA_DISCONNECT_RSP;
1163 alarm_set_on_queue(p_ccb->l2c_ccb_timer,
1164 L2CAP_CHNL_DISCONNECT_TIMEOUT_MS,
1165 l2c_ccb_timer_timeout, p_ccb,
1166 btu_general_alarm_queue);
1167 L2CAP_TRACE_API ("L2CAP - Calling Disconnect_Ind_Cb(), CID: 0x%04x Conf Needed", p_ccb->local_cid);
1168 (*p_ccb->p_rcb->api.pL2CA_DisconnectInd_Cb)(p_ccb->local_cid, TRUE);
1171 case L2CEVT_L2CAP_DATA: /* Peer data packet rcvd */
1172 if ((p_ccb->p_rcb) && (p_ccb->p_rcb->api.pL2CA_DataInd_Cb))
1173 (*p_ccb->p_rcb->api.pL2CA_DataInd_Cb)(p_ccb->local_cid, (BT_HDR *)p_data);
1176 case L2CEVT_L2CA_DISCONNECT_REQ: /* Upper wants to disconnect */
1177 if (p_ccb->p_lcb->transport != BT_TRANSPORT_LE)
1179 /* Make sure we are not in sniff mode */
1181 tBTM_PM_PWR_MD settings;
1182 memset((void*)&settings, 0, sizeof(settings));
1183 settings.mode = BTM_PM_MD_ACTIVE;
1184 BTM_SetPowerMode (BTM_PM_SET_ONLY_ID, p_ccb->p_lcb->remote_bd_addr, &settings);
1188 if (p_ccb->p_lcb->transport == BT_TRANSPORT_LE)
1189 l2cble_send_peer_disc_req (p_ccb);
1191 l2cu_send_peer_disc_req (p_ccb);
1193 p_ccb->chnl_state = CST_W4_L2CAP_DISCONNECT_RSP;
1194 alarm_set_on_queue(p_ccb->l2c_ccb_timer,
1195 L2CAP_CHNL_DISCONNECT_TIMEOUT_MS,
1196 l2c_ccb_timer_timeout, p_ccb,
1197 btu_general_alarm_queue);
1200 case L2CEVT_L2CA_DATA_WRITE: /* Upper layer data to send */
1201 l2c_enqueue_peer_data (p_ccb, (BT_HDR *)p_data);
1202 l2c_link_check_send_pkts (p_ccb->p_lcb, NULL, NULL);
1205 case L2CEVT_L2CA_CONFIG_REQ: /* Upper layer config req */
1206 p_ccb->chnl_state = CST_CONFIG;
1207 p_ccb->config_done &= ~CFG_DONE_MASK;
1208 l2cu_process_our_cfg_req (p_ccb, (tL2CAP_CFG_INFO *)p_data);
1209 l2cu_send_peer_config_req (p_ccb, (tL2CAP_CFG_INFO *)p_data);
1210 alarm_set_on_queue(p_ccb->l2c_ccb_timer,
1211 L2CAP_CHNL_CFG_TIMEOUT_MS,
1212 l2c_ccb_timer_timeout, p_ccb,
1213 btu_general_alarm_queue);
1216 case L2CEVT_TIMEOUT:
1217 /* Process the monitor/retransmission time-outs in flow control/retrans mode */
1218 if (p_ccb->peer_cfg.fcr.mode == L2CAP_FCR_ERTM_MODE)
1219 l2c_fcr_proc_tout (p_ccb);
1222 case L2CEVT_ACK_TIMEOUT:
1223 l2c_fcr_proc_ack_tout (p_ccb);
1226 case L2CEVT_L2CA_SEND_FLOW_CONTROL_CREDIT:
1227 L2CAP_TRACE_DEBUG("%s Sending credit",__func__);
1228 credit = (UINT16*)p_data;
1229 l2cble_send_flow_control_credit(p_ccb, *credit);
1232 case L2CEVT_L2CAP_RECV_FLOW_CONTROL_CREDIT:
1233 credit = (UINT16*)p_data;
1234 L2CAP_TRACE_DEBUG("%s Credits received %d",__func__, *credit);
1235 if((p_ccb->peer_conn_cfg.credits + *credit) > L2CAP_LE_MAX_CREDIT)
1237 /* we have received credits more than max coc credits,
1238 * so disconnecting the Le Coc Channel
1240 l2cble_send_peer_disc_req (p_ccb);
1244 p_ccb->peer_conn_cfg.credits += *credit;
1245 l2c_link_check_send_pkts (p_ccb->p_lcb, NULL, NULL);
1252 /*******************************************************************************
1254 ** Function l2c_csm_w4_l2cap_disconnect_rsp
1256 ** Description This function handles events when the channel is in
1257 ** CST_W4_L2CAP_DISCONNECT_RSP state.
1261 *******************************************************************************/
1262 static void l2c_csm_w4_l2cap_disconnect_rsp (tL2C_CCB *p_ccb, UINT16 event, void *p_data)
1264 tL2CA_DISCONNECT_CFM_CB *disconnect_cfm = p_ccb->p_rcb->api.pL2CA_DisconnectCfm_Cb;
1265 UINT16 local_cid = p_ccb->local_cid;
1267 #if (BT_TRACE_VERBOSE == TRUE)
1268 L2CAP_TRACE_EVENT ("L2CAP - LCID: 0x%04x st: W4_L2CAP_DISC_RSP evt: %s", p_ccb->local_cid, l2c_csm_get_event_name (event));
1270 L2CAP_TRACE_EVENT ("L2CAP - st: W4_L2CAP_DISC_RSP evt: %d", event);
1275 case L2CEVT_L2CAP_DISCONNECT_RSP: /* Peer disconnect response */
1276 l2cu_release_ccb (p_ccb);
1279 L2CAP_TRACE_API ("L2CAP - Calling DisconnectCfm_Cb(), CID: 0x%04x", local_cid);
1280 (*disconnect_cfm)(local_cid, L2CAP_DISC_OK);
1284 case L2CEVT_L2CAP_DISCONNECT_REQ: /* Peer disconnect request */
1285 l2cu_send_peer_disc_rsp (p_ccb->p_lcb, p_ccb->remote_id, p_ccb->local_cid, p_ccb->remote_cid);
1286 l2cu_release_ccb (p_ccb);
1289 L2CAP_TRACE_API ("L2CAP - Calling DisconnectCfm_Cb(), CID: 0x%04x", local_cid);
1290 (*disconnect_cfm)(local_cid, L2CAP_DISC_OK);
1294 case L2CEVT_LP_DISCONNECT_IND: /* Link was disconnected */
1295 case L2CEVT_TIMEOUT: /* Timeout */
1296 l2cu_release_ccb (p_ccb);
1299 L2CAP_TRACE_API ("L2CAP - Calling DisconnectCfm_Cb(), CID: 0x%04x", local_cid);
1300 (*disconnect_cfm)(local_cid, L2CAP_DISC_TIMEOUT);
1304 case L2CEVT_L2CAP_DATA: /* Peer data packet rcvd */
1305 case L2CEVT_L2CA_DATA_WRITE: /* Upper layer data to send */
1309 case L2CEVT_L2CA_SEND_FLOW_CONTROL_CREDIT:
1310 case L2CEVT_L2CAP_RECV_FLOW_CONTROL_CREDIT:
1317 /*******************************************************************************
1319 ** Function l2c_csm_w4_l2ca_disconnect_rsp
1321 ** Description This function handles events when the channel is in
1322 ** CST_W4_L2CA_DISCONNECT_RSP state.
1326 *******************************************************************************/
1327 static void l2c_csm_w4_l2ca_disconnect_rsp (tL2C_CCB *p_ccb, UINT16 event, void *p_data)
1329 tL2CA_DISCONNECT_IND_CB *disconnect_ind = p_ccb->p_rcb->api.pL2CA_DisconnectInd_Cb;
1330 UINT16 local_cid = p_ccb->local_cid;
1332 #if (BT_TRACE_VERBOSE == TRUE)
1333 L2CAP_TRACE_EVENT ("L2CAP - LCID: 0x%04x st: W4_L2CA_DISC_RSP evt: %s", p_ccb->local_cid, l2c_csm_get_event_name (event));
1335 L2CAP_TRACE_EVENT ("L2CAP - st: W4_L2CA_DISC_RSP evt: %d", event);
1340 case L2CEVT_LP_DISCONNECT_IND: /* Link was disconnected */
1341 L2CAP_TRACE_API ("L2CAP - Calling Disconnect_Ind_Cb(), CID: 0x%04x No Conf Needed", p_ccb->local_cid);
1342 l2cu_release_ccb (p_ccb);
1343 (*disconnect_ind)(local_cid, FALSE);
1346 case L2CEVT_TIMEOUT:
1347 l2cu_send_peer_disc_rsp (p_ccb->p_lcb, p_ccb->remote_id, p_ccb->local_cid, p_ccb->remote_cid);
1348 L2CAP_TRACE_API ("L2CAP - Calling Disconnect_Ind_Cb(), CID: 0x%04x No Conf Needed", p_ccb->local_cid);
1349 l2cu_release_ccb (p_ccb);
1350 (*disconnect_ind)(local_cid, FALSE);
1353 case L2CEVT_L2CA_DISCONNECT_REQ: /* Upper disconnect request */
1354 case L2CEVT_L2CA_DISCONNECT_RSP: /* Upper disconnect response */
1355 l2cu_send_peer_disc_rsp (p_ccb->p_lcb, p_ccb->remote_id, p_ccb->local_cid, p_ccb->remote_cid);
1356 l2cu_release_ccb (p_ccb);
1359 case L2CEVT_L2CAP_DATA: /* Peer data packet rcvd */
1360 case L2CEVT_L2CA_DATA_WRITE: /* Upper layer data to send */
1367 #if (BT_TRACE_VERBOSE == TRUE)
1368 /*******************************************************************************
1370 ** Function l2c_csm_get_event_name
1372 ** Description This function returns the event name.
1374 ** NOTE conditionally compiled to save memory.
1376 ** Returns pointer to the name
1378 *******************************************************************************/
1379 static char *l2c_csm_get_event_name (UINT16 event)
1383 case L2CEVT_LP_CONNECT_CFM: /* Lower layer connect confirm */
1384 return ("LOWER_LAYER_CONNECT_CFM");
1385 case L2CEVT_LP_CONNECT_CFM_NEG: /* Lower layer connect confirm (failed) */
1386 return ("LOWER_LAYER_CONNECT_CFM_NEG");
1387 case L2CEVT_LP_CONNECT_IND: /* Lower layer connect indication */
1388 return ("LOWER_LAYER_CONNECT_IND");
1389 case L2CEVT_LP_DISCONNECT_IND: /* Lower layer disconnect indication */
1390 return ("LOWER_LAYER_DISCONNECT_IND");
1391 case L2CEVT_LP_QOS_CFM: /* Lower layer QOS confirmation */
1392 return ("LOWER_LAYER_QOS_CFM");
1393 case L2CEVT_LP_QOS_CFM_NEG: /* Lower layer QOS confirmation (failed)*/
1394 return ("LOWER_LAYER_QOS_CFM_NEG");
1395 case L2CEVT_LP_QOS_VIOLATION_IND: /* Lower layer QOS violation indication */
1396 return ("LOWER_LAYER_QOS_VIOLATION_IND");
1398 case L2CEVT_SEC_COMP: /* Security cleared successfully */
1399 return ("SECURITY_COMPLETE");
1400 case L2CEVT_SEC_COMP_NEG: /* Security procedure failed */
1401 return ("SECURITY_COMPLETE_NEG");
1403 case L2CEVT_L2CAP_CONNECT_REQ: /* Peer connection request */
1404 return ("PEER_CONNECT_REQ");
1405 case L2CEVT_L2CAP_CONNECT_RSP: /* Peer connection response */
1406 return ("PEER_CONNECT_RSP");
1407 case L2CEVT_L2CAP_CONNECT_RSP_PND: /* Peer connection response pending */
1408 return ("PEER_CONNECT_RSP_PND");
1409 case L2CEVT_L2CAP_CONNECT_RSP_NEG: /* Peer connection response (failed) */
1410 return ("PEER_CONNECT_RSP_NEG");
1411 case L2CEVT_L2CAP_CONFIG_REQ: /* Peer configuration request */
1412 return ("PEER_CONFIG_REQ");
1413 case L2CEVT_L2CAP_CONFIG_RSP: /* Peer configuration response */
1414 return ("PEER_CONFIG_RSP");
1415 case L2CEVT_L2CAP_CONFIG_RSP_NEG: /* Peer configuration response (failed) */
1416 return ("PEER_CONFIG_RSP_NEG");
1417 case L2CEVT_L2CAP_DISCONNECT_REQ: /* Peer disconnect request */
1418 return ("PEER_DISCONNECT_REQ");
1419 case L2CEVT_L2CAP_DISCONNECT_RSP: /* Peer disconnect response */
1420 return ("PEER_DISCONNECT_RSP");
1421 case L2CEVT_L2CAP_DATA: /* Peer data */
1422 return ("PEER_DATA");
1424 case L2CEVT_L2CA_CONNECT_REQ: /* Upper layer connect request */
1425 return ("UPPER_LAYER_CONNECT_REQ");
1426 case L2CEVT_L2CA_CONNECT_RSP: /* Upper layer connect response */
1427 return ("UPPER_LAYER_CONNECT_RSP");
1428 case L2CEVT_L2CA_CONNECT_RSP_NEG: /* Upper layer connect response (failed)*/
1429 return ("UPPER_LAYER_CONNECT_RSP_NEG");
1430 case L2CEVT_L2CA_CONFIG_REQ: /* Upper layer config request */
1431 return ("UPPER_LAYER_CONFIG_REQ");
1432 case L2CEVT_L2CA_CONFIG_RSP: /* Upper layer config response */
1433 return ("UPPER_LAYER_CONFIG_RSP");
1434 case L2CEVT_L2CA_CONFIG_RSP_NEG: /* Upper layer config response (failed) */
1435 return ("UPPER_LAYER_CONFIG_RSP_NEG");
1436 case L2CEVT_L2CA_DISCONNECT_REQ: /* Upper layer disconnect request */
1437 return ("UPPER_LAYER_DISCONNECT_REQ");
1438 case L2CEVT_L2CA_DISCONNECT_RSP: /* Upper layer disconnect response */
1439 return ("UPPER_LAYER_DISCONNECT_RSP");
1440 case L2CEVT_L2CA_DATA_READ: /* Upper layer data read */
1441 return ("UPPER_LAYER_DATA_READ");
1442 case L2CEVT_L2CA_DATA_WRITE: /* Upper layer data write */
1443 return ("UPPER_LAYER_DATA_WRITE");
1444 case L2CEVT_TIMEOUT: /* Timeout */
1446 case L2CEVT_SEC_RE_SEND_CMD:
1447 return ("SEC_RE_SEND_CMD");
1448 case L2CEVT_L2CAP_INFO_RSP: /* Peer information response */
1449 return ("L2CEVT_L2CAP_INFO_RSP");
1450 case L2CEVT_ACK_TIMEOUT:
1451 return ("L2CEVT_ACK_TIMEOUT");
1452 case L2CEVT_L2CA_SEND_FLOW_CONTROL_CREDIT: /* Upper layer send credit packet */
1453 return ("SEND_FLOW_CONTROL_CREDIT");
1454 case L2CEVT_L2CAP_RECV_FLOW_CONTROL_CREDIT: /* Peer send credit packet */
1455 return ("RECV_FLOW_CONTROL_CREDIT");
1458 return ("???? UNKNOWN EVENT");
1461 #endif /* (BT_TRACE_VERBOSE == TRUE) */
1464 /*******************************************************************************
1466 ** Function l2c_enqueue_peer_data
1468 ** Description Enqueues data destined for the peer in the ccb. Handles
1469 ** FCR segmentation and checks for congestion.
1473 *******************************************************************************/
1474 void l2c_enqueue_peer_data (tL2C_CCB *p_ccb, BT_HDR *p_buf)
1478 if (p_ccb->peer_cfg.fcr.mode != L2CAP_FCR_BASIC_MODE)
1484 /* Save the channel ID for faster counting */
1485 p_buf->event = p_ccb->local_cid;
1487 /* Step back to add the L2CAP header */
1488 p_buf->offset -= L2CAP_PKT_OVERHEAD;
1489 p_buf->len += L2CAP_PKT_OVERHEAD;
1491 /* Set the pointer to the beginning of the data */
1492 p = (UINT8 *)(p_buf + 1) + p_buf->offset;
1494 /* Now the L2CAP header */
1495 UINT16_TO_STREAM (p, p_buf->len - L2CAP_PKT_OVERHEAD);
1496 UINT16_TO_STREAM (p, p_ccb->remote_cid);
1499 if (p_ccb->xmit_hold_q == NULL) {
1500 L2CAP_TRACE_ERROR("%s: empty queue: p_ccb = %p p_ccb->in_use = %d p_ccb->chnl_state = %d p_ccb->local_cid = %u p_ccb->remote_cid = %u",
1501 __func__, p_ccb, p_ccb->in_use, p_ccb->chnl_state,
1502 p_ccb->local_cid, p_ccb->remote_cid);
1504 fixed_queue_enqueue(p_ccb->xmit_hold_q, p_buf);
1506 l2cu_check_channel_congestion (p_ccb);
1508 #if (L2CAP_ROUND_ROBIN_CHANNEL_SERVICE == TRUE)
1509 /* if new packet is higher priority than serving ccb and it is not overrun */
1510 if (( p_ccb->p_lcb->rr_pri > p_ccb->ccb_priority )
1511 &&( p_ccb->p_lcb->rr_serv[p_ccb->ccb_priority].quota > 0))
1513 /* send out higher priority packet */
1514 p_ccb->p_lcb->rr_pri = p_ccb->ccb_priority;
1518 /* if we are doing a round robin scheduling, set the flag */
1519 if (p_ccb->p_lcb->link_xmit_quota == 0)
1520 l2cb.check_round_robin = TRUE;