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