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