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 state machine and action routines for multiplexer
22 * channel of the RFCOMM unit
23 *
24 ******************************************************************************/
25
26 #include <bluetooth/log.h>
27
28 #include <cstdint>
29
30 #include "osi/include/allocator.h"
31 #include "stack/include/bt_hdr.h"
32 #include "stack/include/bt_psm_types.h"
33 #include "stack/include/l2cap_interface.h"
34 #include "stack/include/l2cdefs.h"
35 #include "stack/rfcomm/port_int.h"
36 #include "stack/rfcomm/rfc_int.h"
37
38 #define L2CAP_SUCCESS 0
39 #define L2CAP_ERROR 1
40
41 using namespace bluetooth;
42
43 /******************************************************************************/
44 /* L O C A L F U N C T I O N P R O T O T Y P E S */
45 /******************************************************************************/
46 static void rfc_mx_sm_state_idle(tRFC_MCB* p_mcb, tRFC_MX_EVENT event, void* p_data);
47 static void rfc_mx_sm_state_wait_conn_cnf(tRFC_MCB* p_mcb, tRFC_MX_EVENT event, void* p_data);
48 static void rfc_mx_sm_state_configure(tRFC_MCB* p_mcb, tRFC_MX_EVENT event, void* p_data);
49 static void rfc_mx_sm_sabme_wait_ua(tRFC_MCB* p_mcb, tRFC_MX_EVENT event, void* p_data);
50 static void rfc_mx_sm_state_wait_sabme(tRFC_MCB* p_mcb, tRFC_MX_EVENT event, void* p_data);
51 static void rfc_mx_sm_state_connected(tRFC_MCB* p_mcb, tRFC_MX_EVENT event, void* p_data);
52 static void rfc_mx_sm_state_disc_wait_ua(tRFC_MCB* p_mcb, tRFC_MX_EVENT event, void* p_data);
53
54 static void rfc_mx_conf_ind(tRFC_MCB* p_mcb, tL2CAP_CFG_INFO* p_cfg);
55 static void rfc_mx_conf_cnf(tRFC_MCB* p_mcb, uint16_t result);
56
57 /*******************************************************************************
58 *
59 * Function rfc_mx_sm_execute
60 *
61 * Description This function sends multiplexer events through the state
62 * machine.
63 *
64 * Returns void
65 *
66 ******************************************************************************/
rfc_mx_sm_execute(tRFC_MCB * p_mcb,tRFC_MX_EVENT event,void * p_data)67 void rfc_mx_sm_execute(tRFC_MCB* p_mcb, tRFC_MX_EVENT event, void* p_data) {
68 log::assert_that(p_mcb != nullptr, "NULL mcb for event {}", event);
69
70 log::info("RFCOMM peer:{} event:{} state:{}", p_mcb->bd_addr, rfcomm_mx_event_text(event),
71 rfcomm_mx_state_text(p_mcb->state));
72
73 switch (p_mcb->state) {
74 case RFC_MX_STATE_IDLE:
75 rfc_mx_sm_state_idle(p_mcb, event, p_data);
76 break;
77
78 case RFC_MX_STATE_WAIT_CONN_CNF:
79 rfc_mx_sm_state_wait_conn_cnf(p_mcb, event, p_data);
80 break;
81
82 case RFC_MX_STATE_CONFIGURE:
83 rfc_mx_sm_state_configure(p_mcb, event, p_data);
84 break;
85
86 case RFC_MX_STATE_SABME_WAIT_UA:
87 rfc_mx_sm_sabme_wait_ua(p_mcb, event, p_data);
88 break;
89
90 case RFC_MX_STATE_WAIT_SABME:
91 rfc_mx_sm_state_wait_sabme(p_mcb, event, p_data);
92 break;
93
94 case RFC_MX_STATE_CONNECTED:
95 rfc_mx_sm_state_connected(p_mcb, event, p_data);
96 break;
97
98 case RFC_MX_STATE_DISC_WAIT_UA:
99 rfc_mx_sm_state_disc_wait_ua(p_mcb, event, p_data);
100 break;
101
102 default:
103 log::error("Received unexpected event:{} in state:{}", rfcomm_mx_event_text(event),
104 rfcomm_mx_state_text(p_mcb->state));
105 }
106 }
107
108 /*******************************************************************************
109 *
110 * Function rfc_mx_sm_state_idle
111 *
112 * Description This function handles events when the multiplexer is in
113 * IDLE state. This state exists when connection is being
114 * initially established.
115 *
116 * Returns void
117 *
118 ******************************************************************************/
rfc_mx_sm_state_idle(tRFC_MCB * p_mcb,tRFC_MX_EVENT event,void *)119 void rfc_mx_sm_state_idle(tRFC_MCB* p_mcb, tRFC_MX_EVENT event, void* /* p_data */) {
120 switch (event) {
121 case RFC_MX_EVENT_START_REQ: {
122 /* Initialize L2CAP MTU */
123 p_mcb->peer_l2cap_mtu = L2CAP_DEFAULT_MTU - RFCOMM_MIN_OFFSET - 1;
124
125 uint16_t lcid = stack::l2cap::get_interface().L2CA_ConnectReq(BT_PSM_RFCOMM, p_mcb->bd_addr);
126 if (lcid == 0) {
127 log::error("failed to open L2CAP channel for {}", p_mcb->bd_addr);
128 rfc_save_lcid_mcb(nullptr, p_mcb->lcid);
129 p_mcb->lcid = 0;
130 PORT_StartCnf(p_mcb, RFCOMM_ERROR);
131 return;
132 }
133 p_mcb->lcid = lcid;
134 /* Save entry for quicker access to mcb based on the LCID */
135 rfc_save_lcid_mcb(p_mcb, p_mcb->lcid);
136
137 p_mcb->state = RFC_MX_STATE_WAIT_CONN_CNF;
138 return;
139 }
140
141 case RFC_MX_EVENT_CONN_IND:
142
143 rfc_timer_start(p_mcb, RFCOMM_CONN_TIMEOUT);
144
145 p_mcb->state = RFC_MX_STATE_CONFIGURE;
146 return;
147
148 case RFC_MX_EVENT_SABME:
149 break;
150
151 case RFC_MX_EVENT_UA:
152 case RFC_MX_EVENT_DM:
153 return;
154
155 case RFC_MX_EVENT_DISC:
156 rfc_send_dm(p_mcb, RFCOMM_MX_DLCI, true);
157 return;
158
159 case RFC_MX_EVENT_UIH:
160 rfc_send_dm(p_mcb, RFCOMM_MX_DLCI, false);
161 return;
162
163 default:
164 log::error("Mx error state {} event {}", rfcomm_mx_state_text(p_mcb->state),
165 rfcomm_mx_event_text(event));
166 return;
167 }
168 log::verbose("RFCOMM MX ignored - evt:{} in state:{}", rfcomm_mx_event_text(event),
169 rfcomm_mx_state_text(p_mcb->state));
170 }
171
172 /*******************************************************************************
173 *
174 * Function rfc_mx_sm_state_wait_conn_cnf
175 *
176 * Description This function handles events when the multiplexer is
177 * waiting for Connection Confirm from L2CAP.
178 *
179 * Returns void
180 *
181 ******************************************************************************/
rfc_mx_sm_state_wait_conn_cnf(tRFC_MCB * p_mcb,tRFC_MX_EVENT event,void * p_data)182 void rfc_mx_sm_state_wait_conn_cnf(tRFC_MCB* p_mcb, tRFC_MX_EVENT event, void* p_data) {
183 switch (event) {
184 case RFC_MX_EVENT_START_REQ:
185 log::error("Mx error state:{} event:{}", rfcomm_mx_state_text(p_mcb->state),
186 rfcomm_mx_event_text(event));
187 return;
188
189 /* There is some new timing so that Config Ind comes before security is
190 completed
191 so we are still waiting fo the confirmation. */
192 case RFC_MX_EVENT_CONF_IND:
193 rfc_mx_conf_ind(p_mcb, (tL2CAP_CFG_INFO*)p_data);
194 return;
195
196 case RFC_MX_EVENT_CONN_CNF:
197 if (*((uint16_t*)p_data) != L2CAP_SUCCESS) {
198 p_mcb->state = RFC_MX_STATE_IDLE;
199
200 PORT_StartCnf(p_mcb, *((uint16_t*)p_data));
201 return;
202 }
203 p_mcb->state = RFC_MX_STATE_CONFIGURE;
204 return;
205
206 case RFC_MX_EVENT_DISC_IND:
207 p_mcb->state = RFC_MX_STATE_IDLE;
208 PORT_CloseInd(p_mcb);
209 return;
210
211 case RFC_MX_EVENT_TIMEOUT:
212 p_mcb->state = RFC_MX_STATE_IDLE;
213 if (!stack::l2cap::get_interface().L2CA_DisconnectReq(p_mcb->lcid)) {
214 log::warn("Unable to send L2CAP disonnect request peer:{} cid:{}", p_mcb->bd_addr,
215 p_mcb->lcid);
216 }
217
218 /* we gave up outgoing connection request then try peer's request */
219 if (p_mcb->pending_lcid) {
220 uint16_t i;
221 uint8_t handle;
222
223 log::verbose("RFCOMM MX retry as acceptor in collision case - evt:{} in state:{}",
224 rfcomm_mx_event_text(event), rfcomm_mx_state_text(p_mcb->state));
225
226 rfc_save_lcid_mcb(NULL, p_mcb->lcid);
227 p_mcb->lcid = p_mcb->pending_lcid;
228 rfc_save_lcid_mcb(p_mcb, p_mcb->lcid);
229
230 p_mcb->is_initiator = false;
231
232 /* update direction bit */
233 for (i = 0; i < RFCOMM_MAX_DLCI; i += 2) {
234 handle = p_mcb->port_handles[i];
235 if (handle != 0) {
236 p_mcb->port_handles[i] = 0;
237 p_mcb->port_handles[i + 1] = handle;
238 rfc_cb.port.port[handle - 1].dlci += 1;
239 log::verbose("RFCOMM MX - DLCI:{} -> {}", i, rfc_cb.port.port[handle - 1].dlci);
240 }
241 }
242
243 rfc_mx_sm_execute(p_mcb, RFC_MX_EVENT_CONN_IND, nullptr);
244 } else {
245 PORT_CloseInd(p_mcb);
246 }
247 return;
248 default:
249 log::error("Received unexpected event:{} in state:{}", rfcomm_mx_event_text(event),
250 rfcomm_mx_state_text(p_mcb->state));
251 }
252 log::verbose("RFCOMM MX ignored - evt:{} in state:{}", rfcomm_mx_event_text(event),
253 rfcomm_mx_state_text(p_mcb->state));
254 }
255
256 /*******************************************************************************
257 *
258 * Function rfc_mx_sm_state_configure
259 *
260 * Description This function handles events when the multiplexer in the
261 * configuration state.
262 *
263 * Returns void
264 *
265 ******************************************************************************/
rfc_mx_sm_state_configure(tRFC_MCB * p_mcb,tRFC_MX_EVENT event,void * p_data)266 void rfc_mx_sm_state_configure(tRFC_MCB* p_mcb, tRFC_MX_EVENT event, void* p_data) {
267 switch (event) {
268 case RFC_MX_EVENT_START_REQ:
269 case RFC_MX_EVENT_CONN_CNF:
270
271 log::error("Mx error state {} event {}", p_mcb->state, event);
272 return;
273
274 case RFC_MX_EVENT_CONF_IND:
275 rfc_mx_conf_ind(p_mcb, (tL2CAP_CFG_INFO*)p_data);
276 return;
277
278 case RFC_MX_EVENT_CONF_CNF:
279 rfc_mx_conf_cnf(p_mcb, (uintptr_t)p_data);
280 return;
281
282 case RFC_MX_EVENT_DISC_IND:
283 p_mcb->state = RFC_MX_STATE_IDLE;
284 PORT_CloseInd(p_mcb);
285 return;
286
287 case RFC_MX_EVENT_TIMEOUT:
288 log::error("L2CAP configuration timeout for {}", p_mcb->bd_addr);
289 p_mcb->state = RFC_MX_STATE_IDLE;
290 if (!stack::l2cap::get_interface().L2CA_DisconnectReq(p_mcb->lcid)) {
291 log::warn("Unable to send L2CAP disonnect request peer:{} cid:{}", p_mcb->bd_addr,
292 p_mcb->lcid);
293 }
294
295 PORT_StartCnf(p_mcb, RFCOMM_ERROR);
296 return;
297 default:
298 log::error("Received unexpected event:{} in state:{}", rfcomm_mx_event_text(event),
299 rfcomm_mx_state_text(p_mcb->state));
300 }
301 log::verbose("RFCOMM MX ignored - evt:{} in state:{}", rfcomm_mx_event_text(event),
302 rfcomm_mx_state_text(p_mcb->state));
303 }
304
305 /*******************************************************************************
306 *
307 * Function rfc_mx_sm_sabme_wait_ua
308 *
309 * Description This function handles events when the multiplexer sent
310 * SABME and is waiting for UA reply.
311 *
312 * Returns void
313 *
314 ******************************************************************************/
rfc_mx_sm_sabme_wait_ua(tRFC_MCB * p_mcb,tRFC_MX_EVENT event,void *)315 void rfc_mx_sm_sabme_wait_ua(tRFC_MCB* p_mcb, tRFC_MX_EVENT event, void* /* p_data */) {
316 switch (event) {
317 case RFC_MX_EVENT_START_REQ:
318 case RFC_MX_EVENT_CONN_CNF:
319 log::error("Mx error state {} event {}", p_mcb->state, event);
320 return;
321
322 /* workaround: we don't support reconfig */
323 /* commented out until we support reconfig
324 case RFC_MX_EVENT_CONF_IND:
325 rfc_mx_conf_ind (p_mcb, (tL2CAP_CFG_INFO *)p_data);
326 return;
327
328 case RFC_MX_EVENT_CONF_CNF:
329 rfc_mx_conf_cnf (p_mcb, (tL2CAP_CFG_INFO *)p_data);
330 return;
331 */
332
333 case RFC_MX_EVENT_DISC_IND:
334 p_mcb->state = RFC_MX_STATE_IDLE;
335 PORT_CloseInd(p_mcb);
336 return;
337
338 case RFC_MX_EVENT_UA:
339 rfc_timer_stop(p_mcb);
340
341 p_mcb->state = RFC_MX_STATE_CONNECTED;
342 p_mcb->peer_ready = true;
343
344 PORT_StartCnf(p_mcb, RFCOMM_SUCCESS);
345 return;
346
347 case RFC_MX_EVENT_DM:
348 rfc_timer_stop(p_mcb);
349 FALLTHROUGH_INTENDED; /* FALLTHROUGH */
350
351 case RFC_MX_EVENT_CONF_IND: /* workaround: we don't support reconfig */
352 case RFC_MX_EVENT_CONF_CNF: /* workaround: we don't support reconfig */
353 case RFC_MX_EVENT_TIMEOUT:
354 p_mcb->state = RFC_MX_STATE_IDLE;
355 if (!stack::l2cap::get_interface().L2CA_DisconnectReq(p_mcb->lcid)) {
356 log::warn("Unable to send L2CAP disonnect request peer:{} cid:{}", p_mcb->bd_addr,
357 p_mcb->lcid);
358 }
359
360 PORT_StartCnf(p_mcb, RFCOMM_ERROR);
361 return;
362 default:
363 log::error("Received unexpected event:{} in state:{}", rfcomm_mx_event_text(event),
364 rfcomm_mx_state_text(p_mcb->state));
365 }
366 log::verbose("RFCOMM MX ignored - evt:{} in state:{}", rfcomm_mx_event_text(event),
367 rfcomm_mx_state_text(p_mcb->state));
368 }
369
370 /*******************************************************************************
371 *
372 * Function rfc_mx_sm_state_wait_sabme
373 *
374 * Description This function handles events when the multiplexer is
375 * waiting for SABME on the acceptor side after configuration
376 *
377 * Returns void
378 *
379 ******************************************************************************/
rfc_mx_sm_state_wait_sabme(tRFC_MCB * p_mcb,tRFC_MX_EVENT event,void * p_data)380 void rfc_mx_sm_state_wait_sabme(tRFC_MCB* p_mcb, tRFC_MX_EVENT event, void* p_data) {
381 switch (event) {
382 case RFC_MX_EVENT_DISC_IND:
383 p_mcb->state = RFC_MX_STATE_IDLE;
384 PORT_CloseInd(p_mcb);
385 return;
386
387 case RFC_MX_EVENT_SABME:
388 if (p_mcb->pending_lcid) {
389 // Channel collision case - at this point we gave up as initiator
390 // and are trying again as acceptor
391 p_mcb->pending_lcid = 0;
392
393 rfc_send_ua(p_mcb, RFCOMM_MX_DLCI);
394
395 rfc_timer_stop(p_mcb);
396 p_mcb->state = RFC_MX_STATE_CONNECTED;
397 p_mcb->peer_ready = true;
398
399 /* MX channel collision has been resolved, continue to open ports */
400 PORT_StartCnf(p_mcb, RFCOMM_SUCCESS);
401 } else {
402 rfc_timer_stop(p_mcb);
403 PORT_StartInd(p_mcb);
404 }
405 return;
406
407 case RFC_MX_EVENT_START_RSP:
408 if (*((uint16_t*)p_data) != RFCOMM_SUCCESS) {
409 rfc_send_dm(p_mcb, RFCOMM_MX_DLCI, true);
410 } else {
411 rfc_send_ua(p_mcb, RFCOMM_MX_DLCI);
412
413 p_mcb->state = RFC_MX_STATE_CONNECTED;
414 p_mcb->peer_ready = true;
415 PORT_StartCnf(p_mcb, RFCOMM_SUCCESS);
416 }
417 return;
418
419 case RFC_MX_EVENT_CONF_IND: /* workaround: we don't support reconfig */
420 case RFC_MX_EVENT_CONF_CNF: /* workaround: we don't support reconfig */
421 case RFC_MX_EVENT_TIMEOUT:
422 p_mcb->state = RFC_MX_STATE_IDLE;
423 if (!stack::l2cap::get_interface().L2CA_DisconnectReq(p_mcb->lcid)) {
424 log::warn("Unable to send L2CAP disonnect request peer:{} cid:{}", p_mcb->bd_addr,
425 p_mcb->lcid);
426 }
427
428 PORT_CloseInd(p_mcb);
429 return;
430
431 default:
432 log::warn("Received unexpected event:{} in state:{}", rfcomm_mx_event_text(event),
433 rfcomm_mx_state_text(p_mcb->state));
434 }
435 log::verbose("RFCOMM MX ignored - evt:{} in state:{}", rfcomm_mx_event_text(event),
436 rfcomm_mx_state_text(p_mcb->state));
437 }
438
439 /*******************************************************************************
440 *
441 * Function rfc_mx_sm_state_connected
442 *
443 * Description This function handles events when the multiplexer is
444 * in the CONNECTED state
445 *
446 * Returns void
447 *
448 ******************************************************************************/
rfc_mx_sm_state_connected(tRFC_MCB * p_mcb,tRFC_MX_EVENT event,void *)449 void rfc_mx_sm_state_connected(tRFC_MCB* p_mcb, tRFC_MX_EVENT event, void* /* p_data */) {
450 switch (event) {
451 case RFC_MX_EVENT_TIMEOUT:
452 case RFC_MX_EVENT_CLOSE_REQ:
453 rfc_timer_start(p_mcb, RFC_DISC_TIMEOUT);
454 p_mcb->state = RFC_MX_STATE_DISC_WAIT_UA;
455 rfc_send_disc(p_mcb, RFCOMM_MX_DLCI);
456 return;
457
458 case RFC_MX_EVENT_DISC_IND:
459 p_mcb->state = RFC_MX_STATE_IDLE;
460 PORT_CloseInd(p_mcb);
461 return;
462
463 case RFC_MX_EVENT_DISC:
464 /* Reply with UA. If initiator bring down L2CAP connection */
465 /* If server wait for some time if client decide to reinitiate channel */
466 rfc_send_ua(p_mcb, RFCOMM_MX_DLCI);
467 if (p_mcb->is_initiator) {
468 if (!stack::l2cap::get_interface().L2CA_DisconnectReq(p_mcb->lcid)) {
469 log::warn("Unable to send L2CAP disonnect request peer:{} cid:{}", p_mcb->bd_addr,
470 p_mcb->lcid);
471 }
472 }
473 /* notify all ports that connection is gone */
474 PORT_CloseInd(p_mcb);
475 return;
476 default:
477 log::error("Received unexpected event:{} in state:{}", rfcomm_mx_event_text(event),
478 rfcomm_mx_state_text(p_mcb->state));
479 }
480 log::verbose("RFCOMM MX ignored - evt:{} in state:{}", rfcomm_mx_event_text(event),
481 rfcomm_mx_state_text(p_mcb->state));
482 }
483
484 /*******************************************************************************
485 *
486 * Function rfc_mx_sm_state_disc_wait_ua
487 *
488 * Description This function handles events when the multiplexer sent
489 * DISC and is waiting for UA reply.
490 *
491 * Returns void
492 *
493 ******************************************************************************/
rfc_mx_sm_state_disc_wait_ua(tRFC_MCB * p_mcb,tRFC_MX_EVENT event,void * p_data)494 void rfc_mx_sm_state_disc_wait_ua(tRFC_MCB* p_mcb, tRFC_MX_EVENT event, void* p_data) {
495 BT_HDR* p_buf;
496 switch (event) {
497 case RFC_MX_EVENT_UA:
498 case RFC_MX_EVENT_DM:
499 case RFC_MX_EVENT_TIMEOUT:
500 if (!stack::l2cap::get_interface().L2CA_DisconnectReq(p_mcb->lcid)) {
501 log::warn("Unable to send L2CAP disonnect request peer:{} cid:{}", p_mcb->bd_addr,
502 p_mcb->lcid);
503 }
504
505 if (p_mcb->restart_required) {
506 /* Start Request was received while disconnecting. Execute it again */
507 uint16_t lcid =
508 stack::l2cap::get_interface().L2CA_ConnectReq(BT_PSM_RFCOMM, p_mcb->bd_addr);
509 if (lcid == 0) {
510 rfc_save_lcid_mcb(NULL, p_mcb->lcid);
511 p_mcb->lcid = 0;
512 PORT_StartCnf(p_mcb, RFCOMM_ERROR);
513 return;
514 }
515 p_mcb->lcid = lcid;
516 /* Save entry for quicker access to mcb based on the LCID */
517 rfc_save_lcid_mcb(p_mcb, p_mcb->lcid);
518
519 /* clean up before reuse it */
520 while ((p_buf = (BT_HDR*)fixed_queue_try_dequeue(p_mcb->cmd_q)) != NULL) {
521 osi_free(p_buf);
522 }
523
524 rfc_timer_start(p_mcb, RFC_MCB_INIT_INACT_TIMER);
525
526 p_mcb->is_initiator = true;
527 p_mcb->restart_required = false;
528
529 p_mcb->state = RFC_MX_STATE_WAIT_CONN_CNF;
530 return;
531 }
532 rfc_release_multiplexer_channel(p_mcb);
533 return;
534
535 case RFC_MX_EVENT_DISC:
536 rfc_send_ua(p_mcb, RFCOMM_MX_DLCI);
537 return;
538
539 case RFC_MX_EVENT_UIH:
540 osi_free(p_data);
541 rfc_send_dm(p_mcb, RFCOMM_MX_DLCI, false);
542 return;
543
544 case RFC_MX_EVENT_START_REQ:
545 p_mcb->restart_required = true;
546 return;
547
548 case RFC_MX_EVENT_DISC_IND:
549 p_mcb->state = RFC_MX_STATE_IDLE;
550 PORT_CloseInd(p_mcb);
551 return;
552
553 case RFC_MX_EVENT_CLOSE_REQ:
554 return;
555
556 case RFC_MX_EVENT_QOS_VIOLATION_IND:
557 break;
558 default:
559 log::error("Received unexpected event:{} in state:{}", rfcomm_mx_event_text(event),
560 rfcomm_mx_state_text(p_mcb->state));
561 }
562 log::verbose("RFCOMM MX ignored - evt:{} in state:{}", rfcomm_mx_event_text(event),
563 rfcomm_mx_state_text(p_mcb->state));
564 }
565
rfc_on_l2cap_error(uint16_t lcid,uint16_t result)566 void rfc_on_l2cap_error(uint16_t lcid, uint16_t result) {
567 tRFC_MCB* p_mcb = rfc_find_lcid_mcb(lcid);
568 if (p_mcb == nullptr) {
569 return;
570 }
571
572 if (static_cast<uint16_t>(result) & L2CAP_CONN_INTERNAL_MASK) {
573 /* if peer rejects our connect request but peer's connect request is pending
574 */
575 if (p_mcb->pending_lcid) {
576 log::verbose("RFCOMM_ConnectCnf retry as acceptor on pending LCID(0x{:x})",
577 p_mcb->pending_lcid);
578
579 /* remove mcb from mapping table */
580 rfc_save_lcid_mcb(NULL, p_mcb->lcid);
581
582 p_mcb->lcid = p_mcb->pending_lcid;
583 p_mcb->is_initiator = false;
584 p_mcb->state = RFC_MX_STATE_IDLE;
585
586 /* store mcb into mapping table */
587 rfc_save_lcid_mcb(p_mcb, p_mcb->lcid);
588
589 /* update direction bit */
590 for (int i = 0; i < RFCOMM_MAX_DLCI; i += 2) {
591 uint8_t handle = p_mcb->port_handles[i];
592 if (handle != 0) {
593 p_mcb->port_handles[i] = 0;
594 p_mcb->port_handles[i + 1] = handle;
595 rfc_cb.port.port[handle - 1].dlci += 1;
596 log::verbose("RFCOMM MX, port_handle={}, DLCI[{}->{}]", handle, i,
597 rfc_cb.port.port[handle - 1].dlci);
598 }
599 }
600 rfc_mx_sm_execute(p_mcb, RFC_MX_EVENT_CONN_IND, nullptr);
601 if (p_mcb->pending_configure_complete) {
602 log::info("Configuration of the pending connection was completed");
603 p_mcb->pending_configure_complete = false;
604 uintptr_t result_as_ptr = static_cast<uint16_t>(tL2CAP_CONN::L2CAP_CONN_OK);
605 rfc_mx_sm_execute(p_mcb, RFC_MX_EVENT_CONF_IND, &p_mcb->pending_cfg_info);
606 rfc_mx_sm_execute(p_mcb, RFC_MX_EVENT_CONF_CNF, (void*)result_as_ptr);
607 }
608 return;
609 }
610
611 p_mcb->lcid = lcid;
612 rfc_mx_sm_execute(p_mcb, RFC_MX_EVENT_CONN_CNF, &result);
613 } else if (result == static_cast<uint16_t>(tL2CAP_CFG_RESULT::L2CAP_CFG_FAILED_NO_REASON)) {
614 log::error("failed to configure L2CAP for {}", p_mcb->bd_addr);
615 if (p_mcb->is_initiator) {
616 log::error("disconnect L2CAP due to config failure for {}", p_mcb->bd_addr);
617 PORT_StartCnf(p_mcb, static_cast<uint16_t>(result));
618 if (!stack::l2cap::get_interface().L2CA_DisconnectReq(p_mcb->lcid)) {
619 log::warn("Unable to send L2CAP disconnect request peer:{} cid:{}", p_mcb->bd_addr,
620 p_mcb->lcid);
621 }
622 }
623 rfc_release_multiplexer_channel(p_mcb);
624 }
625 }
626
627 /*******************************************************************************
628 *
629 * Function rfc_mx_conf_cnf
630 *
631 * Description This function handles L2CA_ConfigCnf message from the
632 * L2CAP. If result is not success tell upper layer that
633 * start has not been accepted. If initiator send SABME
634 * on DLCI 0. T1 is still running.
635 *
636 ******************************************************************************/
rfc_mx_conf_cnf(tRFC_MCB * p_mcb,uint16_t)637 static void rfc_mx_conf_cnf(tRFC_MCB* p_mcb, uint16_t /* result */) {
638 if (p_mcb->state == RFC_MX_STATE_CONFIGURE) {
639 if (p_mcb->is_initiator) {
640 p_mcb->state = RFC_MX_STATE_SABME_WAIT_UA;
641 rfc_send_sabme(p_mcb, RFCOMM_MX_DLCI);
642 rfc_timer_start(p_mcb, RFC_T1_TIMEOUT);
643 } else {
644 p_mcb->state = RFC_MX_STATE_WAIT_SABME;
645 /* increased from T2=20 to CONN=120 to allow user more than 10 sec to type in
646 * the pin, which can be e.d. 16 digits */
647 rfc_timer_start(p_mcb, RFCOMM_CONN_TIMEOUT);
648 }
649 }
650 }
651
652 /*******************************************************************************
653 *
654 * Function rfc_mx_conf_ind
655 *
656 * Description This function handles L2CA_ConfigInd message from the
657 * L2CAP. Send the L2CA_ConfigRsp message.
658 *
659 ******************************************************************************/
rfc_mx_conf_ind(tRFC_MCB * p_mcb,tL2CAP_CFG_INFO * p_cfg)660 static void rfc_mx_conf_ind(tRFC_MCB* p_mcb, tL2CAP_CFG_INFO* p_cfg) {
661 /* Save peer L2CAP MTU if present */
662 /* RFCOMM adds 3-4 bytes in the beginning and 1 bytes FCS */
663 if (p_cfg->mtu_present) {
664 p_mcb->peer_l2cap_mtu = p_cfg->mtu - RFCOMM_MIN_OFFSET - 1;
665 } else {
666 p_mcb->peer_l2cap_mtu = L2CAP_DEFAULT_MTU - RFCOMM_MIN_OFFSET - 1;
667 }
668 }
669