• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
38 extern 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 /******************************************************************************/
43 static void l2c_csm_closed(tL2C_CCB* p_ccb, uint16_t event, void* p_data);
44 static void l2c_csm_orig_w4_sec_comp(tL2C_CCB* p_ccb, uint16_t event,
45                                      void* p_data);
46 static void l2c_csm_term_w4_sec_comp(tL2C_CCB* p_ccb, uint16_t event,
47                                      void* p_data);
48 static void l2c_csm_w4_l2cap_connect_rsp(tL2C_CCB* p_ccb, uint16_t event,
49                                          void* p_data);
50 static void l2c_csm_w4_l2ca_connect_rsp(tL2C_CCB* p_ccb, uint16_t event,
51                                         void* p_data);
52 static void l2c_csm_config(tL2C_CCB* p_ccb, uint16_t event, void* p_data);
53 static void l2c_csm_open(tL2C_CCB* p_ccb, uint16_t event, void* p_data);
54 static void l2c_csm_w4_l2cap_disconnect_rsp(tL2C_CCB* p_ccb, uint16_t event,
55                                             void* p_data);
56 static void l2c_csm_w4_l2ca_disconnect_rsp(tL2C_CCB* p_ccb, uint16_t event,
57                                            void* p_data);
58 
59 static 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  ******************************************************************************/
l2c_csm_execute(tL2C_CCB * p_ccb,uint16_t event,void * p_data)70 void 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  ******************************************************************************/
l2c_csm_closed(tL2C_CCB * p_ccb,uint16_t event,void * p_data)131 static 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  ******************************************************************************/
l2c_csm_orig_w4_sec_comp(tL2C_CCB * p_ccb,uint16_t event,void * p_data)313 static 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  ******************************************************************************/
l2c_csm_term_w4_sec_comp(tL2C_CCB * p_ccb,uint16_t event,void * p_data)419 static 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  ******************************************************************************/
l2c_csm_w4_l2cap_connect_rsp(tL2C_CCB * p_ccb,uint16_t event,void * p_data)532 static 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  ******************************************************************************/
l2c_csm_w4_l2ca_connect_rsp(tL2C_CCB * p_ccb,uint16_t event,void * p_data)662 static 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  ******************************************************************************/
l2c_csm_config(tL2C_CCB * p_ccb,uint16_t event,void * p_data)767 static 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  ******************************************************************************/
l2c_csm_open(tL2C_CCB * p_ccb,uint16_t event,void * p_data)1013 static 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  ******************************************************************************/
l2c_csm_w4_l2cap_disconnect_rsp(tL2C_CCB * p_ccb,uint16_t event,void * p_data)1189 static 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  ******************************************************************************/
l2c_csm_w4_l2ca_disconnect_rsp(tL2C_CCB * p_ccb,uint16_t event,void * p_data)1251 static 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  ******************************************************************************/
l2c_csm_get_event_name(uint16_t event)1304 static 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  ******************************************************************************/
l2c_enqueue_peer_data(tL2C_CCB * p_ccb,BT_HDR * p_buf)1396 void 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