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