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