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