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 * Port Emulation entity utilities
22 *
23 ******************************************************************************/
24
25 #define LOG_TAG "rfcomm_port_utils"
26
27 #include <bluetooth/log.h>
28
29 #include <cstdint>
30 #include <cstring>
31
32 #include "internal_include/bt_target.h"
33 #include "osi/include/allocator.h"
34 #include "osi/include/mutex.h"
35 #include "stack/include/bt_hdr.h"
36 #include "stack/include/btm_client_interface.h"
37 #include "stack/include/l2cdefs.h"
38 #include "stack/rfcomm/port_int.h"
39 #include "stack/rfcomm/rfc_int.h"
40 #include "types/raw_address.h"
41
42 using namespace bluetooth;
43
44 static const PortSettings default_port_settings = {
45 PORT_BAUD_RATE_9600,
46 PORT_8_BITS,
47 PORT_ONESTOPBIT,
48 PORT_PARITY_NO,
49 PORT_ODD_PARITY,
50 PORT_FC_OFF,
51 0, /* No rx_char */
52 PORT_XON_DC1,
53 PORT_XOFF_DC3,
54 };
55
56 /*******************************************************************************
57 *
58 * Function port_allocate_port
59 *
60 * Description Look through the Port Control Blocks for a free one. Note
61 * that one server can open several ports with the same SCN
62 * if it can support simulteneous requests from different
63 * clients.
64 *
65 * Returns Pointer to the PORT or NULL if not found
66 *
67 ******************************************************************************/
port_allocate_port(uint8_t dlci,const RawAddress & bd_addr)68 tPORT* port_allocate_port(uint8_t dlci, const RawAddress& bd_addr) {
69 uint8_t port_index = rfc_cb.rfc.last_port_index + static_cast<uint8_t>(1);
70 // Loop at most MAX_RFC_PORTS items
71 for (int loop_counter = 0; loop_counter < MAX_RFC_PORTS; loop_counter++, port_index++) {
72 if (port_index >= MAX_RFC_PORTS) {
73 port_index = 0;
74 }
75 tPORT* p_port = &rfc_cb.port.port[port_index];
76 if (!p_port->in_use) {
77 // Assume that we already called port_release_port on this
78 memset(p_port, 0, sizeof(tPORT));
79 p_port->in_use = true;
80 // handle is a port handle starting from 1
81 p_port->handle = port_index + static_cast<uint8_t>(1);
82 // During the open set default state for the port connection
83 port_set_defaults(p_port);
84 p_port->rfc.port_timer = alarm_new("rfcomm_port.port_timer");
85 p_port->dlci = dlci;
86 p_port->bd_addr = bd_addr;
87 rfc_cb.rfc.last_port_index = port_index;
88 log::verbose("rfc_cb.port.port[{}]:{} chosen, last_port_index:{}, bd_addr={}", port_index,
89 std::format_ptr(p_port), rfc_cb.rfc.last_port_index, bd_addr);
90 return p_port;
91 }
92 }
93 log::warn("running out of free ports for dlci {}, bd_addr {}", dlci, bd_addr);
94 return nullptr;
95 }
96
97 /*******************************************************************************
98 *
99 * Function port_set_defaults
100 *
101 * Description Set defualt port parameters
102 *
103 *
104 ******************************************************************************/
port_set_defaults(tPORT * p_port)105 void port_set_defaults(tPORT* p_port) {
106 p_port->ev_mask = 0;
107 p_port->p_callback = nullptr;
108 p_port->port_ctrl = 0;
109 p_port->line_status = 0;
110 p_port->rx_flag_ev_pending = false;
111 p_port->peer_mtu = RFCOMM_DEFAULT_MTU;
112
113 p_port->user_port_settings = default_port_settings;
114 p_port->peer_port_settings = default_port_settings;
115
116 p_port->credit_tx = 0;
117 p_port->credit_rx = 0;
118
119 memset(&p_port->local_ctrl, 0, sizeof(p_port->local_ctrl));
120 memset(&p_port->peer_ctrl, 0, sizeof(p_port->peer_ctrl));
121 memset(&p_port->rx, 0, sizeof(p_port->rx));
122 memset(&p_port->tx, 0, sizeof(p_port->tx));
123
124 p_port->tx.queue = fixed_queue_new(SIZE_MAX);
125 p_port->rx.queue = fixed_queue_new(SIZE_MAX);
126 }
127
128 /*******************************************************************************
129 *
130 * Function port_select_mtu
131 *
132 * Description Select MTU which will best serve connection from our
133 * point of view.
134 * If our device is 1.2 or lower we calculate how many DH5s
135 * fit into 1 RFCOMM buffer.
136 *
137 *
138 ******************************************************************************/
port_select_mtu(tPORT * p_port)139 void port_select_mtu(tPORT* p_port) {
140 uint16_t packet_size;
141
142 /* Will select MTU only if application did not setup something */
143 if (p_port->mtu == 0) {
144 /* find packet size which connection supports */
145 packet_size = get_btm_client_interface().peer.BTM_GetMaxPacketSize(p_port->bd_addr);
146 if (packet_size == 0) {
147 /* something is very wrong */
148 log::warn("bad packet size 0 for{}", p_port->bd_addr);
149 p_port->mtu = RFCOMM_DEFAULT_MTU;
150 } else {
151 /* We try to negotiate MTU that each packet can be split into whole
152 number of max packets. For example if link is 1.2 max packet size is 339
153 bytes.
154 At first calculate how many whole packets it is. MAX L2CAP is 1691 + 4
155 overhead.
156 1695, that will be 5 Dh5 packets. Now maximum RFCOMM packet is
157 5 * 339 = 1695. Minus 4 bytes L2CAP header 1691. Minus RFCOMM 6 bytes
158 header overhead 1685
159
160 For EDR 2.0 packet size is 1027. So we better send RFCOMM packet as 1
161 3DH5 packet
162 1 * 1027 = 1027. Minus 4 bytes L2CAP header 1023. Minus RFCOMM 6 bytes
163 header overhead 1017 */
164 if ((L2CAP_MTU_SIZE + L2CAP_PKT_OVERHEAD) >= packet_size) {
165 p_port->mtu = ((L2CAP_MTU_SIZE + L2CAP_PKT_OVERHEAD) / packet_size * packet_size) -
166 RFCOMM_DATA_OVERHEAD - L2CAP_PKT_OVERHEAD;
167 log::verbose("selected {} based on connection speed", p_port->mtu);
168 } else {
169 p_port->mtu = L2CAP_MTU_SIZE - RFCOMM_DATA_OVERHEAD;
170 log::verbose("selected {} based on l2cap PDU size", p_port->mtu);
171 }
172 }
173 } else {
174 log::verbose("application selected {}", p_port->mtu);
175 }
176 p_port->credit_rx_max = (PORT_RX_HIGH_WM / p_port->mtu);
177 if (p_port->credit_rx_max > PORT_RX_BUF_HIGH_WM) {
178 p_port->credit_rx_max = PORT_RX_BUF_HIGH_WM;
179 }
180 p_port->credit_rx_low = (PORT_RX_LOW_WM / p_port->mtu);
181 if (p_port->credit_rx_low > PORT_RX_BUF_LOW_WM) {
182 p_port->credit_rx_low = PORT_RX_BUF_LOW_WM;
183 }
184 p_port->rx_buf_critical = (PORT_RX_CRITICAL_WM / p_port->mtu);
185 if (p_port->rx_buf_critical > PORT_RX_BUF_CRITICAL_WM) {
186 p_port->rx_buf_critical = PORT_RX_BUF_CRITICAL_WM;
187 }
188 log::verbose("credit_rx_max {}, credit_rx_low {}, rx_buf_critical {}", p_port->credit_rx_max,
189 p_port->credit_rx_low, p_port->rx_buf_critical);
190 }
191
192 /*******************************************************************************
193 *
194 * Function port_release_port
195 *
196 * Description Release port control block.
197 *
198 * Returns Pointer to the PORT or NULL if not found
199 *
200 ******************************************************************************/
port_release_port(tPORT * p_port)201 void port_release_port(tPORT* p_port) {
202 log::verbose("p_port: {} state: {} keep_handle: {}", std::format_ptr(p_port), p_port->rfc.state,
203 p_port->keep_port_handle);
204
205 mutex_global_lock();
206 BT_HDR* p_buf;
207 while ((p_buf = (BT_HDR*)fixed_queue_try_dequeue(p_port->rx.queue)) != nullptr) {
208 osi_free(p_buf);
209 }
210 p_port->rx.queue_size = 0;
211
212 while ((p_buf = (BT_HDR*)fixed_queue_try_dequeue(p_port->tx.queue)) != nullptr) {
213 osi_free(p_buf);
214 }
215 p_port->tx.queue_size = 0;
216 mutex_global_unlock();
217
218 alarm_cancel(p_port->rfc.port_timer);
219
220 p_port->state = PORT_CONNECTION_STATE_CLOSED;
221
222 if (p_port->rfc.state == RFC_STATE_CLOSED) {
223 if (p_port->rfc.p_mcb) {
224 p_port->rfc.p_mcb->port_handles[p_port->dlci] = 0;
225
226 /* If there are no more ports opened on this MCB release it */
227 rfc_check_mcb_active(p_port->rfc.p_mcb);
228 }
229
230 rfc_port_timer_stop(p_port);
231
232 mutex_global_lock();
233 fixed_queue_free(p_port->tx.queue, nullptr);
234 p_port->tx.queue = nullptr;
235 fixed_queue_free(p_port->rx.queue, nullptr);
236 p_port->rx.queue = nullptr;
237 mutex_global_unlock();
238
239 if (p_port->keep_port_handle) {
240 log::verbose("Re-initialize handle: {}", p_port->handle);
241
242 /* save event mask and callback */
243 uint32_t mask = p_port->ev_mask;
244 tPORT_CALLBACK* p_port_cb = p_port->p_callback;
245 PortSettings user_port_settings = p_port->user_port_settings;
246
247 port_set_defaults(p_port);
248
249 /* restore */
250 p_port->ev_mask = mask;
251 p_port->p_callback = p_port_cb;
252 p_port->user_port_settings = user_port_settings;
253 p_port->mtu = p_port->keep_mtu;
254
255 p_port->state = PORT_CONNECTION_STATE_OPENING;
256 p_port->rfc.p_mcb = nullptr;
257 if (p_port->is_server) {
258 p_port->dlci &= 0xfe;
259 }
260
261 p_port->local_ctrl.modem_signal = p_port->default_signal_state;
262 p_port->bd_addr = RawAddress::kAny;
263 } else {
264 log::verbose("Clean-up handle: {}", p_port->handle);
265 alarm_free(p_port->rfc.port_timer);
266 memset(p_port, 0, sizeof(tPORT));
267 }
268 }
269 }
270
271 /*******************************************************************************
272 *
273 * Function port_find_mcb
274 *
275 * Description This function checks if connection exists to device with
276 * the address.
277 *
278 ******************************************************************************/
port_find_mcb(const RawAddress & bd_addr)279 tRFC_MCB* port_find_mcb(const RawAddress& bd_addr) {
280 for (tRFC_MCB& mcb : rfc_cb.port.rfc_mcb) {
281 if ((mcb.state != RFC_MX_STATE_IDLE) && (mcb.bd_addr == bd_addr)) {
282 /* Multiplexer channel found do not change anything */
283 log::verbose("found, bd_addr:{}, rfc_mcb:{}, lcid:0x{:x}", bd_addr, std::format_ptr(&mcb),
284 mcb.lcid);
285 return &mcb;
286 }
287 }
288 log::warn("not found, bd_addr:{}", bd_addr);
289 return nullptr;
290 }
291
292 /*******************************************************************************
293 *
294 * Function port_find_mcb_dlci_port
295 *
296 * Description Find port on the multiplexer channel based on DLCI. If
297 * this port with DLCI not found try to use even DLCI. This
298 * is for the case when client is establishing connection on
299 * none-initiator MCB.
300 *
301 * Returns Pointer to the PORT or NULL if not found
302 *
303 ******************************************************************************/
port_find_mcb_dlci_port(tRFC_MCB * p_mcb,uint8_t dlci)304 tPORT* port_find_mcb_dlci_port(tRFC_MCB* p_mcb, uint8_t dlci) {
305 if (!p_mcb) {
306 log::error("p_mcb is null, dlci={}", dlci);
307 return nullptr;
308 }
309
310 if (dlci > RFCOMM_MAX_DLCI) {
311 log::warn("DLCI {} is too large, bd_addr={}, p_mcb={}", dlci, p_mcb->bd_addr,
312 std::format_ptr(p_mcb));
313 return nullptr;
314 }
315
316 uint8_t handle = p_mcb->port_handles[dlci];
317 if (handle == 0) {
318 log::info("Cannot find allocated RFCOMM app port for DLCI {} on {}, p_mcb={}", dlci,
319 p_mcb->bd_addr, std::format_ptr(p_mcb));
320 return nullptr;
321 }
322 return &rfc_cb.port.port[handle - 1];
323 }
324
325 /*******************************************************************************
326 *
327 * Function port_find_dlci_port
328 *
329 * Description Find port with DLCI not assigned to multiplexer channel
330 *
331 * Returns Pointer to the PORT or NULL if not found
332 *
333 ******************************************************************************/
port_find_dlci_port(uint8_t dlci)334 tPORT* port_find_dlci_port(uint8_t dlci) {
335 for (tPORT& port : rfc_cb.port.port) {
336 if (port.in_use && (port.rfc.p_mcb == nullptr)) {
337 if (port.dlci == dlci) {
338 return &port;
339 } else if ((dlci & 0x01) && (port.dlci == (dlci - 1))) {
340 port.dlci++;
341 return &port;
342 }
343 }
344 }
345 return nullptr;
346 }
347
348 /*******************************************************************************
349 *
350 * Function port_find_port
351 *
352 * Description Find port with DLCI, address
353 *
354 * Returns Pointer to the PORT or NULL if not found
355 *
356 ******************************************************************************/
port_find_port(uint8_t dlci,const RawAddress & bd_addr)357 tPORT* port_find_port(uint8_t dlci, const RawAddress& bd_addr) {
358 for (tPORT& port : rfc_cb.port.port) {
359 if (port.in_use && (port.dlci == dlci) && (port.bd_addr == bd_addr)) {
360 return &port;
361 }
362 }
363 return nullptr;
364 }
365
366 /*******************************************************************************
367 *
368 * Function port_flow_control_user
369 *
370 * Description Check the current user flow control and if necessary return
371 * events to be send to the user based on the user's specified
372 * flow control type.
373 *
374 * Returns event mask to be returned to the application
375 *
376 ******************************************************************************/
port_flow_control_user(tPORT * p_port)377 uint32_t port_flow_control_user(tPORT* p_port) {
378 uint32_t event = 0;
379
380 /* Flow control to the user can be caused by flow controlling by the peer */
381 /* (FlowInd, or flow control by the peer RFCOMM (Fcon) or internally if */
382 /* tx_queue is full */
383 bool fc = p_port->tx.peer_fc || !p_port->rfc.p_mcb || !p_port->rfc.p_mcb->peer_ready ||
384 (p_port->tx.queue_size > PORT_TX_HIGH_WM) ||
385 (fixed_queue_length(p_port->tx.queue) > PORT_TX_BUF_HIGH_WM);
386
387 if (p_port->tx.user_fc == fc) {
388 return 0;
389 }
390
391 p_port->tx.user_fc = fc;
392
393 if (fc) {
394 event = PORT_EV_FC;
395 } else {
396 event = PORT_EV_FC | PORT_EV_FCS;
397 }
398
399 return event;
400 }
401
402 /*******************************************************************************
403 *
404 * Function port_get_signal_changes
405 *
406 * Description Check modem signals that has been changed
407 *
408 * Returns event mask to be returned to the application
409 *
410 ******************************************************************************/
port_get_signal_changes(tPORT * p_port,uint8_t old_signals,uint8_t signal)411 uint32_t port_get_signal_changes(tPORT* p_port, uint8_t old_signals, uint8_t signal) {
412 uint8_t changed_signals = (signal ^ old_signals);
413 uint32_t events = 0;
414
415 if (changed_signals & PORT_DTRDSR_ON) {
416 events |= PORT_EV_DSR;
417
418 if (signal & PORT_DTRDSR_ON) {
419 events |= PORT_EV_DSRS;
420 }
421 }
422
423 if (changed_signals & PORT_CTSRTS_ON) {
424 events |= PORT_EV_CTS;
425
426 if (signal & PORT_CTSRTS_ON) {
427 events |= PORT_EV_CTSS;
428 }
429 }
430
431 if (changed_signals & PORT_RING_ON) {
432 events |= PORT_EV_RING;
433 }
434
435 if (changed_signals & PORT_DCD_ON) {
436 events |= PORT_EV_RLSD;
437
438 if (signal & PORT_DCD_ON) {
439 events |= PORT_EV_RLSDS;
440 }
441 }
442
443 return p_port->ev_mask & events;
444 }
445
446 /*******************************************************************************
447 *
448 * Function port_flow_control_peer
449 *
450 * Description Send flow control messages to the peer for both enabling
451 * and disabling flow control, for both credit-based and
452 * TS 07.10 flow control mechanisms.
453 *
454 * Returns nothing
455 *
456 ******************************************************************************/
port_flow_control_peer(tPORT * p_port,bool enable,uint16_t count)457 void port_flow_control_peer(tPORT* p_port, bool enable, uint16_t count) {
458 if (!p_port->rfc.p_mcb) {
459 return;
460 }
461
462 /* If using credit based flow control */
463 if (p_port->rfc.p_mcb->flow == PORT_FC_CREDIT) {
464 /* if want to enable flow from peer */
465 if (enable) {
466 /* update rx credits */
467 if (count > p_port->credit_rx) {
468 p_port->credit_rx = 0;
469 } else {
470 p_port->credit_rx -= count;
471 }
472
473 /* If credit count is less than low credit watermark, and user */
474 /* did not force flow control, send a credit update */
475 /* There might be a special case when we just adjusted rx_max */
476 if ((p_port->credit_rx <= p_port->credit_rx_low) && !p_port->rx.user_fc &&
477 (p_port->credit_rx_max > p_port->credit_rx)) {
478 rfc_send_credit(p_port->rfc.p_mcb, p_port->dlci,
479 (uint8_t)(p_port->credit_rx_max - p_port->credit_rx));
480
481 p_port->credit_rx = p_port->credit_rx_max;
482
483 p_port->rx.peer_fc = false;
484 }
485 } else {
486 /* else want to disable flow from peer */
487 /* if client registered data callback, just do what they want */
488 if (p_port->p_data_callback || p_port->p_data_co_callback) {
489 p_port->rx.peer_fc = true;
490 } else if (fixed_queue_length(p_port->rx.queue) >= p_port->credit_rx_max) {
491 /* if queue count reached credit rx max, set peer fc */
492 p_port->rx.peer_fc = true;
493 }
494 }
495 } else {
496 /* else using TS 07.10 flow control */
497 /* if want to enable flow from peer */
498 if (enable) {
499 /* If rfcomm suspended traffic from the peer based on the rx_queue_size */
500 /* check if it can be resumed now */
501 if (p_port->rx.peer_fc && (p_port->rx.queue_size < PORT_RX_LOW_WM) &&
502 (fixed_queue_length(p_port->rx.queue) < PORT_RX_BUF_LOW_WM)) {
503 p_port->rx.peer_fc = false;
504
505 /* If user did not force flow control allow traffic now */
506 if (!p_port->rx.user_fc) {
507 RFCOMM_FlowReq(p_port->rfc.p_mcb, p_port->dlci, true);
508 }
509 }
510 } else {
511 /* else want to disable flow from peer */
512 /* if client registered data callback, just do what they want */
513 if (p_port->p_data_callback || p_port->p_data_co_callback) {
514 p_port->rx.peer_fc = true;
515 RFCOMM_FlowReq(p_port->rfc.p_mcb, p_port->dlci, false);
516 } else if (((p_port->rx.queue_size > PORT_RX_HIGH_WM) ||
517 (fixed_queue_length(p_port->rx.queue) > PORT_RX_BUF_HIGH_WM)) &&
518 !p_port->rx.peer_fc) {
519 /* Check the size of the rx queue. If it exceeds certain */
520 /* level and flow control has not been sent to the peer do it now */
521 log::verbose("PORT_DataInd Data reached HW. Sending FC set.");
522
523 p_port->rx.peer_fc = true;
524 RFCOMM_FlowReq(p_port->rfc.p_mcb, p_port->dlci, false);
525 }
526 }
527 }
528 }
529