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 "bt_common.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
40extern fixed_queue_t *btu_general_alarm_queue;
41
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/********************************************************************************/
45static void l2c_csm_closed (tL2C_CCB *p_ccb, UINT16 event, void *p_data);
46static void l2c_csm_orig_w4_sec_comp (tL2C_CCB *p_ccb, UINT16 event, void *p_data);
47static void l2c_csm_term_w4_sec_comp (tL2C_CCB *p_ccb, UINT16 event, void *p_data);
48static void l2c_csm_w4_l2cap_connect_rsp (tL2C_CCB *p_ccb, UINT16 event, void *p_data);
49static void l2c_csm_w4_l2ca_connect_rsp (tL2C_CCB *p_ccb, UINT16 event, void *p_data);
50static void l2c_csm_config (tL2C_CCB *p_ccb, UINT16 event, void *p_data);
51static void l2c_csm_open (tL2C_CCB *p_ccb, UINT16 event, void *p_data);
52static void l2c_csm_w4_l2cap_disconnect_rsp (tL2C_CCB *p_ccb, UINT16 event, void *p_data);
53static void l2c_csm_w4_l2ca_disconnect_rsp (tL2C_CCB *p_ccb, UINT16 event, void *p_data);
54
55#if (BT_TRACE_VERBOSE == TRUE)
56static char *l2c_csm_get_event_name (UINT16 event);
57#endif
58
59/*******************************************************************************
60**
61** Function         l2c_csm_execute
62**
63** Description      This function executes the state machine.
64**
65** Returns          void
66**
67*******************************************************************************/
68void l2c_csm_execute (tL2C_CCB *p_ccb, UINT16 event, void *p_data)
69{
70    switch (p_ccb->chnl_state)
71    {
72    case CST_CLOSED:
73        l2c_csm_closed (p_ccb, event, p_data);
74        break;
75
76    case CST_ORIG_W4_SEC_COMP:
77        l2c_csm_orig_w4_sec_comp (p_ccb, event, p_data);
78        break;
79
80    case CST_TERM_W4_SEC_COMP:
81        l2c_csm_term_w4_sec_comp (p_ccb, event, p_data);
82        break;
83
84    case CST_W4_L2CAP_CONNECT_RSP:
85        l2c_csm_w4_l2cap_connect_rsp (p_ccb, event, p_data);
86        break;
87
88    case CST_W4_L2CA_CONNECT_RSP:
89        l2c_csm_w4_l2ca_connect_rsp (p_ccb, event, p_data);
90        break;
91
92    case CST_CONFIG:
93        l2c_csm_config (p_ccb, event, p_data);
94        break;
95
96    case CST_OPEN:
97        l2c_csm_open (p_ccb, event, p_data);
98        break;
99
100    case CST_W4_L2CAP_DISCONNECT_RSP:
101        l2c_csm_w4_l2cap_disconnect_rsp (p_ccb, event, p_data);
102        break;
103
104    case CST_W4_L2CA_DISCONNECT_RSP:
105        l2c_csm_w4_l2ca_disconnect_rsp (p_ccb, event, p_data);
106        break;
107
108    default:
109        L2CAP_TRACE_DEBUG("Unhandled event! event = %d",event);
110        break;
111    }
112}
113
114/*******************************************************************************
115**
116** Function         l2c_csm_closed
117**
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.
121**
122** Returns          void
123**
124*******************************************************************************/
125static void l2c_csm_closed (tL2C_CCB *p_ccb, UINT16 event, void *p_data)
126{
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;
131
132    if (p_ccb->p_rcb == NULL)
133    {
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));
136#else
137        L2CAP_TRACE_ERROR ("L2CAP - LCID: 0x%04x  st: CLOSED  evt: 0x%04x p_rcb == NULL", p_ccb->local_cid, event);
138#endif
139        return;
140    }
141
142#if (L2CAP_UCD_INCLUDED == TRUE)
143    if ( local_cid == L2CAP_CONNECTIONLESS_CID )
144    {
145        /* check if this event can be processed by UCD */
146        if ( l2c_ucd_process_event (p_ccb, event, p_data) )
147        {
148            /* The event is processed by UCD state machine */
149            return;
150        }
151    }
152#endif
153
154    disconnect_ind = p_ccb->p_rcb->api.pL2CA_DisconnectInd_Cb;
155    connect_cfm    = p_ccb->p_rcb->api.pL2CA_ConnectCfm_Cb;
156
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));
159#else
160    L2CAP_TRACE_EVENT ("L2CAP - st: CLOSED evt: %d", event);
161#endif
162
163    switch (event)
164    {
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);
169        break;
170
171    case L2CEVT_LP_CONNECT_CFM:                         /* Link came up         */
172        if (p_ccb->p_lcb->transport == BT_TRANSPORT_LE)
173        {
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);
177        }
178        else
179        {
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);
183        }
184        break;
185
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))
190        {
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);
194        }
195        break;
196
197    case L2CEVT_L2CA_CONNECT_REQ:                       /* API connect request  */
198        if (p_ccb->p_lcb->transport == BT_TRANSPORT_LE)
199        {
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);
203        }
204        else
205        {
206            /* Cancel sniff mode if needed */
207            {
208                tBTM_PM_PWR_MD settings;
209                memset((void*)&settings, 0, sizeof(settings));
210                settings.mode = BTM_PM_MD_ACTIVE;
211/* COVERITY
212Event uninit_use_in_call: Using uninitialized value "settings" (field "settings".timeout uninitialized) in call to function "BTM_SetPowerMode" [details]
213Event uninit_use_in_call: Using uninitialized value "settings.max" in call to function "BTM_SetPowerMode" [details]
214Event 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
217*/
218                BTM_SetPowerMode (BTM_PM_SET_ONLY_ID, p_ccb->p_lcb->remote_bd_addr, &settings);
219            }
220
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;
225        }
226        break;
227
228    case L2CEVT_SEC_COMP:
229        p_ccb->chnl_state = CST_W4_L2CAP_CONNECT_RSP;
230
231        /* Wait for the info resp in this state before sending connect req (if needed) */
232        if (!p_ccb->p_lcb->w4_info_rsp)
233        {
234            /* Need to have at least one compatible channel to continue */
235            if (!l2c_fcr_chk_chan_modes(p_ccb))
236            {
237                l2cu_release_ccb (p_ccb);
238                (*p_ccb->p_rcb->api.pL2CA_ConnectCfm_Cb)(local_cid, L2CAP_CONN_NO_LINK);
239            }
240            else
241            {
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);
247            }
248        }
249        break;
250
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);
255        break;
256
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);
260
261        if (p_ccb->p_lcb->transport == BT_TRANSPORT_LE)
262        {
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);
266        }
267        else
268        {
269            /* Cancel sniff mode if needed */
270            {
271                tBTM_PM_PWR_MD settings;
272                memset((void*)&settings, 0, sizeof(settings));
273                settings.mode = BTM_PM_MD_ACTIVE;
274/* COVERITY
275Event uninit_use_in_call: Using uninitialized value "settings" (field "settings".timeout uninitialized) in call to function "BTM_SetPowerMode" [details]
276Event uninit_use_in_call: Using uninitialized value "settings.max" in call to function "BTM_SetPowerMode" [details]
277Event 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
280*/
281                BTM_SetPowerMode (BTM_PM_SET_ONLY_ID, p_ccb->p_lcb->remote_bd_addr, &settings);
282            }
283
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)
287            {
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);
290            }
291        }
292        break;
293
294    case L2CEVT_TIMEOUT:
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);
298        break;
299
300    case L2CEVT_L2CAP_DATA:                         /* Peer data packet rcvd    */
301    case L2CEVT_L2CA_DATA_WRITE:                    /* Upper layer data to send */
302        osi_free(p_data);
303        break;
304
305    case L2CEVT_L2CA_DISCONNECT_REQ:                 /* Upper wants to disconnect */
306        l2cu_release_ccb (p_ccb);
307        break;
308
309    case L2CEVT_L2CA_SEND_FLOW_CONTROL_CREDIT:
310    case L2CEVT_L2CAP_RECV_FLOW_CONTROL_CREDIT:
311        osi_free(p_data);
312        break;
313    }
314}
315
316
317/*******************************************************************************
318**
319** Function         l2c_csm_orig_w4_sec_comp
320**
321** Description      This function handles events when the channel is in
322**                  CST_ORIG_W4_SEC_COMP state.
323**
324** Returns          void
325**
326*******************************************************************************/
327static void l2c_csm_orig_w4_sec_comp (tL2C_CCB *p_ccb, UINT16 event, void *p_data)
328{
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;
332
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));
335#else
336    L2CAP_TRACE_EVENT ("L2CAP - st: ORIG_W4_SEC_COMP evt: %d", event);
337#endif
338
339#if (L2CAP_UCD_INCLUDED == TRUE)
340    if ( local_cid == L2CAP_CONNECTIONLESS_CID )
341    {
342        /* check if this event can be processed by UCD */
343        if ( l2c_ucd_process_event (p_ccb, event, p_data) )
344        {
345            /* The event is processed by UCD state machine */
346            return;
347        }
348    }
349#endif
350
351    switch (event)
352    {
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);
357        break;
358
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)
362        {
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);
365        }
366        else
367        {
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);
370        }
371        break;
372
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)
377        {
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     */
383        }
384        else
385        {
386            if (!p_ccb->p_lcb->w4_info_rsp)
387            {
388                /* Need to have at least one compatible channel to continue */
389                if (!l2c_fcr_chk_chan_modes(p_ccb))
390                {
391                    l2cu_release_ccb (p_ccb);
392                    (*connect_cfm)(local_cid, L2CAP_CONN_NO_LINK);
393                }
394                else
395                {
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     */
401                }
402            }
403        }
404        break;
405
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);
408
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) )
412        {
413            p_ccb->p_lcb->idle_timeout = 0;
414        }
415
416        l2cu_release_ccb (p_ccb);
417        (*connect_cfm)(local_cid, HCI_ERR_AUTH_FAILURE);
418        break;
419
420    case L2CEVT_L2CA_DATA_WRITE:                    /* Upper layer data to send */
421    case L2CEVT_L2CAP_DATA:                         /* Peer data packet rcvd    */
422        osi_free(p_data);
423        break;
424
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);
428
429        l2cu_release_ccb (p_ccb);
430        break;
431    }
432}
433
434
435/*******************************************************************************
436**
437** Function         l2c_csm_term_w4_sec_comp
438**
439** Description      This function handles events when the channel is in
440**                  CST_TERM_W4_SEC_COMP state.
441**
442** Returns          void
443**
444*******************************************************************************/
445static void l2c_csm_term_w4_sec_comp (tL2C_CCB *p_ccb, UINT16 event, void *p_data)
446{
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));
449#else
450    L2CAP_TRACE_EVENT ("L2CAP - st: TERM_W4_SEC_COMP evt: %d", event);
451#endif
452
453#if (L2CAP_UCD_INCLUDED == TRUE)
454    if ( p_ccb->local_cid == L2CAP_CONNECTIONLESS_CID )
455    {
456        /* check if this event can be processed by UCD */
457        if ( l2c_ucd_process_event (p_ccb, event, p_data) )
458        {
459            /* The event is processed by UCD state machine */
460            return;
461        }
462    }
463#endif
464
465    switch (event)
466    {
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);
470
471        l2cu_release_ccb (p_ccb);
472        break;
473
474    case L2CEVT_SEC_COMP:
475        p_ccb->chnl_state = CST_W4_L2CA_CONNECT_RSP;
476
477        /* Wait for the info resp in next state before sending connect ind (if needed) */
478        if (!p_ccb->p_lcb->w4_info_rsp)
479        {
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);
486
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);
489        }
490        else
491        {
492            /*
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
499            */
500
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);
503        }
504        break;
505
506    case L2CEVT_SEC_COMP_NEG:
507        if (((tL2C_CONN_INFO *)p_data)->status == BTM_DELAY_CHECK)
508        {
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);
514        }
515        else
516        {
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);
519            else
520                l2cu_send_peer_connect_rsp (p_ccb, L2CAP_CONN_SECURITY_BLOCK, 0);
521            l2cu_release_ccb (p_ccb);
522        }
523        break;
524
525    case L2CEVT_L2CA_DATA_WRITE:                    /* Upper layer data to send */
526    case L2CEVT_L2CAP_DATA:                         /* Peer data packet rcvd    */
527        osi_free(p_data);
528        break;
529
530    case L2CEVT_L2CA_DISCONNECT_REQ:                 /* Upper wants to disconnect */
531        l2cu_release_ccb (p_ccb);
532        break;
533
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);
536
537        /* Tell security manager to abort */
538        btm_sec_abort_access_req (p_ccb->p_lcb->remote_bd_addr);
539
540        l2cu_release_ccb (p_ccb);
541        break;
542
543    case L2CEVT_TIMEOUT:
544        /* SM4 related. */
545        if (!btsnd_hcic_disconnect (p_ccb->p_lcb->handle, HCI_ERR_AUTH_FAILURE))
546        {
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);
551        }
552        break;
553
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);
557        break;
558    }
559}
560
561
562/*******************************************************************************
563**
564** Function         l2c_csm_w4_l2cap_connect_rsp
565**
566** Description      This function handles events when the channel is in
567**                  CST_W4_L2CAP_CONNECT_RSP state.
568**
569** Returns          void
570**
571*******************************************************************************/
572static void l2c_csm_w4_l2cap_connect_rsp (tL2C_CCB *p_ccb, UINT16 event, void *p_data)
573{
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;
578
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));
581#else
582    L2CAP_TRACE_EVENT ("L2CAP - st: W4_L2CAP_CON_RSP evt: %d", event);
583#endif
584
585    switch (event)
586    {
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))
592        {
593            L2CAP_TRACE_API ("L2CAP - Calling Disconnect_Ind_Cb(), CID: 0x%04x  No Conf Needed",
594                              p_ccb->local_cid);
595            l2cu_release_ccb (p_ccb);
596            (*disconnect_ind)(local_cid, FALSE);
597        }
598        p_ccb->flags |= CCB_FLAG_NO_RETRY;
599        break;
600
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)
604        {
605            /* Connection is completed */
606            alarm_cancel(p_ccb->l2c_ccb_timer);
607            p_ccb->chnl_state = CST_OPEN;
608        }
609        else
610        {
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);
615        }
616        L2CAP_TRACE_API ("L2CAP - Calling Connect_Cfm_Cb(), CID: 0x%04x, Success", p_ccb->local_cid);
617
618        (*p_ccb->p_rcb->api.pL2CA_ConnectCfm_Cb)(local_cid, L2CAP_CONN_OK);
619        break;
620
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)
628        {
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);
631        }
632        break;
633
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);
638        break;
639
640    case L2CEVT_TIMEOUT:
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);
644        break;
645
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)
649        {
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);
656        }
657        else
658            l2cu_release_ccb (p_ccb);
659        break;
660
661    case L2CEVT_L2CA_DATA_WRITE:                    /* Upper layer data to send */
662    case L2CEVT_L2CAP_DATA:                         /* Peer data packet rcvd    */
663        osi_free(p_data);
664        break;
665
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))
669        {
670            l2cu_release_ccb (p_ccb);
671            (*connect_cfm)(local_cid, L2CAP_CONN_NO_LINK);
672        }
673        else
674        {
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     */
681        }
682        break;
683
684    case L2CEVT_L2CA_SEND_FLOW_CONTROL_CREDIT:
685    case L2CEVT_L2CAP_RECV_FLOW_CONTROL_CREDIT:
686        osi_free(p_data);
687        break;
688    }
689}
690
691
692/*******************************************************************************
693**
694** Function         l2c_csm_w4_l2ca_connect_rsp
695**
696** Description      This function handles events when the channel is in
697**                  CST_W4_L2CA_CONNECT_RSP state.
698**
699** Returns          void
700**
701*******************************************************************************/
702static void l2c_csm_w4_l2ca_connect_rsp (tL2C_CCB *p_ccb, UINT16 event, void *p_data)
703{
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;
707
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));
710#else
711    L2CAP_TRACE_EVENT ("L2CAP - st: W4_L2CA_CON_RSP evt: %d", event);
712#endif
713
714    switch (event)
715    {
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);
720        break;
721
722    case L2CEVT_L2CA_CONNECT_RSP:
723        p_ci = (tL2C_CONN_INFO *)p_data;
724        if (p_ccb->p_lcb->transport == BT_TRANSPORT_LE)
725        {
726            /* Result should be OK or Reject */
727            if ((!p_ci) || (p_ci->l2cap_result == L2CAP_CONN_OK))
728            {
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);
732            }
733            else
734            {
735                l2cble_credit_based_conn_res (p_ccb, p_ci->l2cap_result);
736                l2cu_release_ccb (p_ccb);
737            }
738        }
739        else
740        {
741            /* Result should be OK or PENDING */
742            if ((!p_ci) || (p_ci->l2cap_result == L2CAP_CONN_OK))
743            {
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);
750            }
751            else
752            {
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);
759            }
760        }
761        break;
762
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);
767        else
768            l2cu_send_peer_connect_rsp (p_ccb, p_ci->l2cap_result, p_ci->l2cap_status);
769        l2cu_release_ccb (p_ccb);
770        break;
771
772    case L2CEVT_TIMEOUT:
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);
777        break;
778
779    case L2CEVT_L2CA_DATA_WRITE:                    /* Upper layer data to send */
780    case L2CEVT_L2CAP_DATA:                         /* Peer data packet rcvd    */
781        osi_free(p_data);
782        break;
783
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);
791        break;
792
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);
800
801        (*p_ccb->p_rcb->api.pL2CA_ConnectInd_Cb) (p_ccb->p_lcb->remote_bd_addr,
802                                                  p_ccb->local_cid,
803                                                  p_ccb->p_rcb->psm,
804                                                  p_ccb->remote_id);
805        break;
806    }
807}
808
809
810/*******************************************************************************
811**
812** Function         l2c_csm_config
813**
814** Description      This function handles events when the channel is in
815**                  CONFIG state.
816**
817** Returns          void
818**
819*******************************************************************************/
820static void l2c_csm_config (tL2C_CCB *p_ccb, UINT16 event, void *p_data)
821{
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;
825    UINT8                   cfg_result;
826
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));
829#else
830    L2CAP_TRACE_EVENT ("L2CAP - st: CONFIG evt: %d", event);
831#endif
832
833    switch (event)
834    {
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);
839        break;
840
841    case L2CEVT_L2CAP_CONFIG_REQ:                  /* Peer config request   */
842
843        if ((cfg_result = l2cu_process_peer_cfg_req (p_ccb, p_cfg)) == L2CAP_PEER_CFG_OK)
844        {
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);
848        }
849        else if (cfg_result == L2CAP_PEER_CFG_DISCONNECT)
850        {
851            /* Disconnect if channels are incompatible */
852            L2CAP_TRACE_EVENT ("L2CAP - incompatible configurations disconnect");
853            l2cu_disconnect_chnl (p_ccb);
854        }
855        else /* Return error to peer so he can renegotiate if possible */
856        {
857            L2CAP_TRACE_EVENT ("L2CAP - incompatible configurations trying reconfig");
858            l2cu_send_peer_config_rsp (p_ccb, p_cfg);
859        }
860        break;
861
862    case L2CEVT_L2CAP_CONFIG_RSP:                  /* Peer config response  */
863         l2cu_process_peer_cfg_rsp (p_ccb, p_cfg);
864
865         if (p_cfg->result != L2CAP_CFG_PENDING)
866         {
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
871              */
872             p_ccb->config_done |= OB_CFG_DONE;
873
874             if (p_ccb->config_done & IB_CFG_DONE)
875             {
876                /* Verify two sides are in compatible modes before continuing */
877                if (p_ccb->our_cfg.fcr.mode != p_ccb->peer_cfg.fcr.mode)
878                {
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);
883                    break;
884                }
885
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);
890
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);
894
895                /*
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
898                */
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)))
901                {
902                    l2c_fcr_adj_monitor_retran_timeout (p_ccb);
903                }
904
905#if (L2CAP_ERTM_STATS == TRUE)
906                p_ccb->fcrb.connect_tick_count = time_get_os_boottime_ms();
907#endif
908                /* See if we can forward anything on the hold queue */
909                if (!fixed_queue_is_empty(p_ccb->xmit_hold_q))
910                {
911                    l2c_link_check_send_pkts (p_ccb->p_lcb, NULL, NULL);
912                }
913            }
914        }
915
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);
918        break;
919
920    case L2CEVT_L2CAP_CONFIG_RSP_NEG:              /* Peer config error rsp */
921        /* Disable the Timer */
922         alarm_cancel(p_ccb->l2c_ccb_timer);
923
924        /* If failure was channel mode try to renegotiate */
925        if (l2c_fcr_renegotiate_chan(p_ccb, p_cfg) == FALSE)
926        {
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);
929        }
930        break;
931
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);
940        break;
941
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);
949        break;
950
951    case L2CEVT_L2CA_CONFIG_RSP:                   /* Upper layer config rsp   */
952        l2cu_process_our_cfg_rsp (p_ccb, p_cfg);
953
954        /* Not finished if continuation flag is set */
955        if ( (p_cfg->flags & L2CAP_CFG_FLAGS_MASK_CONT) || (p_cfg->result == L2CAP_CFG_PENDING) )
956        {
957            /* Send intermediate response; remain in cfg state */
958            l2cu_send_peer_config_rsp (p_ccb, p_cfg);
959            break;
960        }
961
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;
966
967        p_ccb->config_done |= IB_CFG_DONE;
968
969        if (p_ccb->config_done & OB_CFG_DONE)
970        {
971            /* Verify two sides are in compatible modes before continuing */
972            if (p_ccb->our_cfg.fcr.mode != p_ccb->peer_cfg.fcr.mode)
973            {
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);
978                break;
979            }
980
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);
985        }
986
987        l2cu_send_peer_config_rsp (p_ccb, p_cfg);
988
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);
992
993#if (L2CAP_ERTM_STATS == TRUE)
994        p_ccb->fcrb.connect_tick_count = time_get_os_boottime_ms();
995#endif
996
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)))
1000        {
1001            l2c_link_check_send_pkts (p_ccb->p_lcb, NULL, NULL);
1002        }
1003        break;
1004
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);
1011        break;
1012
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);
1020        break;
1021
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)
1027        {
1028            if (p_ccb->local_cid < L2CAP_BASE_APPL_CID)
1029            {
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);
1033                else
1034                    osi_free(p_data);
1035            break;
1036            }
1037        }
1038#endif
1039        (*p_ccb->p_rcb->api.pL2CA_DataInd_Cb)(p_ccb->local_cid, (BT_HDR *)p_data);
1040        break;
1041
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);
1045        else
1046            osi_free(p_data);
1047        break;
1048
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",
1052                p_ccb->local_cid);
1053        l2cu_release_ccb (p_ccb);
1054        (*disconnect_ind)(local_cid, FALSE);
1055        break;
1056    }
1057}
1058
1059
1060/*******************************************************************************
1061**
1062** Function         l2c_csm_open
1063**
1064** Description      This function handles events when the channel is in
1065**                  OPEN state.
1066**
1067** Returns          void
1068**
1069*******************************************************************************/
1070static void l2c_csm_open (tL2C_CCB *p_ccb, UINT16 event, void *p_data)
1071{
1072    UINT16                  local_cid = p_ccb->local_cid;
1073    tL2CAP_CFG_INFO         *p_cfg;
1074    tL2C_CHNL_STATE         tempstate;
1075    UINT8                   tempcfgdone;
1076    UINT8                   cfg_result;
1077    UINT16                  *credit;
1078
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));
1082#else
1083    L2CAP_TRACE_EVENT ("L2CAP - st: OPEN evt: %d", event);
1084#endif
1085
1086#if (L2CAP_UCD_INCLUDED == TRUE)
1087    if ( local_cid == L2CAP_CONNECTIONLESS_CID )
1088    {
1089        /* check if this event can be processed by UCD */
1090        if ( l2c_ucd_process_event (p_ccb, event, p_data) )
1091        {
1092            /* The event is processed by UCD state machine */
1093            return;
1094        }
1095    }
1096#endif
1097
1098    switch (event)
1099    {
1100    case L2CEVT_LP_DISCONNECT_IND:                  /* Link was disconnected */
1101        L2CAP_TRACE_API ("L2CAP - Calling Disconnect_Ind_Cb(), CID: 0x%04x  No Conf Needed",
1102                p_ccb->local_cid);
1103        l2cu_release_ccb (p_ccb);
1104        if (p_ccb->p_rcb)
1105            (*p_ccb->p_rcb->api.pL2CA_DisconnectInd_Cb)(local_cid, FALSE);
1106        break;
1107
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);
1112        break;
1113
1114    case L2CEVT_L2CAP_CONFIG_REQ:                  /* Peer config request   */
1115        p_cfg = (tL2CAP_CFG_INFO *)p_data;
1116
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;
1121
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);
1126
1127        if ((cfg_result = l2cu_process_peer_cfg_req (p_ccb, p_cfg)) == L2CAP_PEER_CFG_OK)
1128        {
1129            (*p_ccb->p_rcb->api.pL2CA_ConfigInd_Cb)(p_ccb->local_cid, p_cfg);
1130        }
1131
1132        /* Error in config parameters: reset state and config flag */
1133        else if (cfg_result == L2CAP_PEER_CFG_UNACCEPTABLE)
1134        {
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);
1139        }
1140        else    /* L2CAP_PEER_CFG_DISCONNECT */
1141        {
1142            /* Disconnect if channels are incompatible
1143             * Note this should not occur if reconfigure
1144             * since this should have never passed original config.
1145             */
1146            l2cu_disconnect_chnl (p_ccb);
1147        }
1148        break;
1149
1150    case L2CEVT_L2CAP_DISCONNECT_REQ:                  /* Peer disconnected request */
1151        if (p_ccb->p_lcb->transport != BT_TRANSPORT_LE)
1152        {
1153        /* Make sure we are not in sniff mode */
1154            {
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);
1159            }
1160        }
1161
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);
1169        break;
1170
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);
1174        break;
1175
1176    case L2CEVT_L2CA_DISCONNECT_REQ:                 /* Upper wants to disconnect */
1177        if (p_ccb->p_lcb->transport != BT_TRANSPORT_LE)
1178        {
1179            /* Make sure we are not in sniff mode */
1180            {
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);
1185            }
1186        }
1187
1188        if (p_ccb->p_lcb->transport == BT_TRANSPORT_LE)
1189            l2cble_send_peer_disc_req (p_ccb);
1190        else
1191            l2cu_send_peer_disc_req (p_ccb);
1192
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);
1198        break;
1199
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);
1203        break;
1204
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);
1214        break;
1215
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);
1220        break;
1221
1222    case L2CEVT_ACK_TIMEOUT:
1223        l2c_fcr_proc_ack_tout (p_ccb);
1224        break;
1225
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);
1230        break;
1231
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)
1236        {
1237            /* we have received credits more than max coc credits,
1238             * so disconnecting the Le Coc Channel
1239             */
1240            l2cble_send_peer_disc_req (p_ccb);
1241        }
1242        else
1243        {
1244            p_ccb->peer_conn_cfg.credits += *credit;
1245            l2c_link_check_send_pkts (p_ccb->p_lcb, NULL, NULL);
1246        }
1247        break;
1248    }
1249}
1250
1251
1252/*******************************************************************************
1253**
1254** Function         l2c_csm_w4_l2cap_disconnect_rsp
1255**
1256** Description      This function handles events when the channel is in
1257**                  CST_W4_L2CAP_DISCONNECT_RSP state.
1258**
1259** Returns          void
1260**
1261*******************************************************************************/
1262static void l2c_csm_w4_l2cap_disconnect_rsp (tL2C_CCB *p_ccb, UINT16 event, void *p_data)
1263{
1264    tL2CA_DISCONNECT_CFM_CB *disconnect_cfm = p_ccb->p_rcb->api.pL2CA_DisconnectCfm_Cb;
1265    UINT16                  local_cid = p_ccb->local_cid;
1266
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));
1269#else
1270    L2CAP_TRACE_EVENT ("L2CAP - st: W4_L2CAP_DISC_RSP evt: %d", event);
1271#endif
1272
1273    switch (event)
1274    {
1275    case L2CEVT_L2CAP_DISCONNECT_RSP:                /* Peer disconnect response */
1276        l2cu_release_ccb (p_ccb);
1277        if (disconnect_cfm)
1278        {
1279            L2CAP_TRACE_API ("L2CAP - Calling DisconnectCfm_Cb(), CID: 0x%04x", local_cid);
1280            (*disconnect_cfm)(local_cid, L2CAP_DISC_OK);
1281        }
1282        break;
1283
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);
1287        if (disconnect_cfm)
1288        {
1289            L2CAP_TRACE_API ("L2CAP - Calling DisconnectCfm_Cb(), CID: 0x%04x", local_cid);
1290            (*disconnect_cfm)(local_cid, L2CAP_DISC_OK);
1291        }
1292       break;
1293
1294    case L2CEVT_LP_DISCONNECT_IND:                  /* Link was disconnected */
1295    case L2CEVT_TIMEOUT:                            /* Timeout */
1296        l2cu_release_ccb (p_ccb);
1297        if (disconnect_cfm)
1298        {
1299            L2CAP_TRACE_API ("L2CAP - Calling DisconnectCfm_Cb(), CID: 0x%04x", local_cid);
1300            (*disconnect_cfm)(local_cid, L2CAP_DISC_TIMEOUT);
1301        }
1302        break;
1303
1304    case L2CEVT_L2CAP_DATA:                         /* Peer data packet rcvd    */
1305    case L2CEVT_L2CA_DATA_WRITE:                    /* Upper layer data to send */
1306        osi_free(p_data);
1307        break;
1308
1309    case L2CEVT_L2CA_SEND_FLOW_CONTROL_CREDIT:
1310    case L2CEVT_L2CAP_RECV_FLOW_CONTROL_CREDIT:
1311        osi_free(p_data);
1312        break;
1313    }
1314}
1315
1316
1317/*******************************************************************************
1318**
1319** Function         l2c_csm_w4_l2ca_disconnect_rsp
1320**
1321** Description      This function handles events when the channel is in
1322**                  CST_W4_L2CA_DISCONNECT_RSP state.
1323**
1324** Returns          void
1325**
1326*******************************************************************************/
1327static void l2c_csm_w4_l2ca_disconnect_rsp (tL2C_CCB *p_ccb, UINT16 event, void *p_data)
1328{
1329    tL2CA_DISCONNECT_IND_CB *disconnect_ind = p_ccb->p_rcb->api.pL2CA_DisconnectInd_Cb;
1330    UINT16                  local_cid = p_ccb->local_cid;
1331
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));
1334#else
1335    L2CAP_TRACE_EVENT ("L2CAP - st: W4_L2CA_DISC_RSP evt: %d", event);
1336#endif
1337
1338    switch (event)
1339    {
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);
1344        break;
1345
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);
1351        break;
1352
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);
1357        break;
1358
1359    case L2CEVT_L2CAP_DATA:                         /* Peer data packet rcvd    */
1360    case L2CEVT_L2CA_DATA_WRITE:                    /* Upper layer data to send */
1361        osi_free(p_data);
1362        break;
1363    }
1364}
1365
1366
1367#if (BT_TRACE_VERBOSE == TRUE)
1368/*******************************************************************************
1369**
1370** Function         l2c_csm_get_event_name
1371**
1372** Description      This function returns the event name.
1373**
1374** NOTE             conditionally compiled to save memory.
1375**
1376** Returns          pointer to the name
1377**
1378*******************************************************************************/
1379static char *l2c_csm_get_event_name (UINT16 event)
1380{
1381    switch (event)
1382    {
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");
1397
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");
1402
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");
1423
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                              */
1445        return ("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");
1456
1457    default:
1458        return ("???? UNKNOWN EVENT");
1459    }
1460}
1461#endif /* (BT_TRACE_VERBOSE == TRUE) */
1462
1463
1464/*******************************************************************************
1465**
1466** Function         l2c_enqueue_peer_data
1467**
1468** Description      Enqueues data destined for the peer in the ccb. Handles
1469**                  FCR segmentation and checks for congestion.
1470**
1471** Returns          void
1472**
1473*******************************************************************************/
1474void l2c_enqueue_peer_data (tL2C_CCB *p_ccb, BT_HDR *p_buf)
1475{
1476    UINT8       *p;
1477
1478    if (p_ccb->peer_cfg.fcr.mode != L2CAP_FCR_BASIC_MODE)
1479    {
1480        p_buf->event = 0;
1481    }
1482    else
1483    {
1484        /* Save the channel ID for faster counting */
1485        p_buf->event = p_ccb->local_cid;
1486
1487        /* Step back to add the L2CAP header */
1488        p_buf->offset -= L2CAP_PKT_OVERHEAD;
1489        p_buf->len    += L2CAP_PKT_OVERHEAD;
1490
1491        /* Set the pointer to the beginning of the data */
1492        p = (UINT8 *)(p_buf + 1) + p_buf->offset;
1493
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);
1497    }
1498
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);
1503    }
1504    fixed_queue_enqueue(p_ccb->xmit_hold_q, p_buf);
1505
1506    l2cu_check_channel_congestion (p_ccb);
1507
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))
1512    {
1513        /* send out higher priority packet */
1514        p_ccb->p_lcb->rr_pri = p_ccb->ccb_priority;
1515    }
1516#endif
1517
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;
1521}
1522
1523
1524