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