• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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),
203                p_port->rfc.sm_cb.state, 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.sm_cb.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     p_port->rfc.sm_cb = {};
232 
233     mutex_global_lock();
234     fixed_queue_free(p_port->tx.queue, nullptr);
235     p_port->tx.queue = nullptr;
236     fixed_queue_free(p_port->rx.queue, nullptr);
237     p_port->rx.queue = nullptr;
238     mutex_global_unlock();
239 
240     if (p_port->keep_port_handle) {
241       log::verbose("Re-initialize handle: {}", p_port->handle);
242 
243       /* save event mask and callback */
244       uint32_t mask = p_port->ev_mask;
245       tPORT_CALLBACK* p_port_cb = p_port->p_callback;
246       PortSettings user_port_settings = p_port->user_port_settings;
247 
248       port_set_defaults(p_port);
249 
250       /* restore */
251       p_port->ev_mask = mask;
252       p_port->p_callback = p_port_cb;
253       p_port->user_port_settings = user_port_settings;
254       p_port->mtu = p_port->keep_mtu;
255 
256       p_port->state = PORT_CONNECTION_STATE_OPENING;
257       p_port->rfc.p_mcb = nullptr;
258       if (p_port->is_server) {
259         p_port->dlci &= 0xfe;
260       }
261 
262       p_port->local_ctrl.modem_signal = p_port->default_signal_state;
263       p_port->bd_addr = RawAddress::kAny;
264     } else {
265       log::verbose("Clean-up handle: {}", p_port->handle);
266       alarm_free(p_port->rfc.port_timer);
267       memset(p_port, 0, sizeof(tPORT));
268     }
269   }
270 }
271 
272 /*******************************************************************************
273  *
274  * Function         port_find_mcb
275  *
276  * Description      This function checks if connection exists to device with
277  *                  the address.
278  *
279  ******************************************************************************/
port_find_mcb(const RawAddress & bd_addr)280 tRFC_MCB* port_find_mcb(const RawAddress& bd_addr) {
281   for (tRFC_MCB& mcb : rfc_cb.port.rfc_mcb) {
282     if ((mcb.state != RFC_MX_STATE_IDLE) && (mcb.bd_addr == bd_addr)) {
283       /* Multiplexer channel found do not change anything */
284       log::verbose("found, bd_addr:{}, rfc_mcb:{}, lcid:0x{:x}", bd_addr, std::format_ptr(&mcb),
285                    mcb.lcid);
286       return &mcb;
287     }
288   }
289   log::warn("not found, bd_addr:{}", bd_addr);
290   return nullptr;
291 }
292 
293 /*******************************************************************************
294  *
295  * Function         port_find_mcb_dlci_port
296  *
297  * Description      Find port on the multiplexer channel based on DLCI.  If
298  *                  this port with DLCI not found try to use even DLCI.  This
299  *                  is for the case when client is establishing connection on
300  *                  none-initiator MCB.
301  *
302  * Returns          Pointer to the PORT or NULL if not found
303  *
304  ******************************************************************************/
port_find_mcb_dlci_port(tRFC_MCB * p_mcb,uint8_t dlci)305 tPORT* port_find_mcb_dlci_port(tRFC_MCB* p_mcb, uint8_t dlci) {
306   if (!p_mcb) {
307     log::error("p_mcb is null, dlci={}", dlci);
308     return nullptr;
309   }
310 
311   if (dlci > RFCOMM_MAX_DLCI) {
312     log::warn("DLCI {} is too large, bd_addr={}, p_mcb={}", dlci, p_mcb->bd_addr,
313               std::format_ptr(p_mcb));
314     return nullptr;
315   }
316 
317   uint8_t handle = p_mcb->port_handles[dlci];
318   if (handle == 0) {
319     log::info("Cannot find allocated RFCOMM app port for DLCI {} on {}, p_mcb={}", dlci,
320               p_mcb->bd_addr, std::format_ptr(p_mcb));
321     return nullptr;
322   }
323   return &rfc_cb.port.port[handle - 1];
324 }
325 
326 /*******************************************************************************
327  *
328  * Function         port_find_dlci_port
329  *
330  * Description      Find port with DLCI not assigned to multiplexer channel
331  *
332  * Returns          Pointer to the PORT or NULL if not found
333  *
334  ******************************************************************************/
port_find_dlci_port(uint8_t dlci)335 tPORT* port_find_dlci_port(uint8_t dlci) {
336   for (tPORT& port : rfc_cb.port.port) {
337     if (port.in_use && (port.rfc.p_mcb == nullptr)) {
338       if (port.dlci == dlci) {
339         return &port;
340       } else if ((dlci & 0x01) && (port.dlci == (dlci - 1))) {
341         port.dlci++;
342         return &port;
343       }
344     }
345   }
346   return nullptr;
347 }
348 
349 /*******************************************************************************
350  *
351  * Function         port_find_port
352  *
353  * Description      Find port with DLCI, address
354  *
355  * Returns          Pointer to the PORT or NULL if not found
356  *
357  ******************************************************************************/
port_find_port(uint8_t dlci,const RawAddress & bd_addr)358 tPORT* port_find_port(uint8_t dlci, const RawAddress& bd_addr) {
359   for (tPORT& port : rfc_cb.port.port) {
360     if (port.in_use && (port.dlci == dlci) && (port.bd_addr == bd_addr)) {
361       return &port;
362     }
363   }
364   return nullptr;
365 }
366 
367 /*******************************************************************************
368  *
369  * Function         port_flow_control_user
370  *
371  * Description      Check the current user flow control and if necessary return
372  *                  events to be send to the user based on the user's specified
373  *                  flow control type.
374  *
375  * Returns          event mask to be returned to the application
376  *
377  ******************************************************************************/
port_flow_control_user(tPORT * p_port)378 uint32_t port_flow_control_user(tPORT* p_port) {
379   uint32_t event = 0;
380 
381   /* Flow control to the user can be caused by flow controlling by the peer */
382   /* (FlowInd, or flow control by the peer RFCOMM (Fcon) or internally if */
383   /* tx_queue is full */
384   bool fc = p_port->tx.peer_fc || !p_port->rfc.p_mcb || !p_port->rfc.p_mcb->peer_ready ||
385             (p_port->tx.queue_size > PORT_TX_HIGH_WM) ||
386             (fixed_queue_length(p_port->tx.queue) > PORT_TX_BUF_HIGH_WM);
387 
388   if (p_port->tx.user_fc == fc) {
389     return 0;
390   }
391 
392   p_port->tx.user_fc = fc;
393 
394   if (fc) {
395     event = PORT_EV_FC;
396   } else {
397     event = PORT_EV_FC | PORT_EV_FCS;
398   }
399 
400   return event;
401 }
402 
403 /*******************************************************************************
404  *
405  * Function         port_get_signal_changes
406  *
407  * Description      Check modem signals that has been changed
408  *
409  * Returns          event mask to be returned to the application
410  *
411  ******************************************************************************/
port_get_signal_changes(tPORT * p_port,uint8_t old_signals,uint8_t signal)412 uint32_t port_get_signal_changes(tPORT* p_port, uint8_t old_signals, uint8_t signal) {
413   uint8_t changed_signals = (signal ^ old_signals);
414   uint32_t events = 0;
415 
416   if (changed_signals & PORT_DTRDSR_ON) {
417     events |= PORT_EV_DSR;
418 
419     if (signal & PORT_DTRDSR_ON) {
420       events |= PORT_EV_DSRS;
421     }
422   }
423 
424   if (changed_signals & PORT_CTSRTS_ON) {
425     events |= PORT_EV_CTS;
426 
427     if (signal & PORT_CTSRTS_ON) {
428       events |= PORT_EV_CTSS;
429     }
430   }
431 
432   if (changed_signals & PORT_RING_ON) {
433     events |= PORT_EV_RING;
434   }
435 
436   if (changed_signals & PORT_DCD_ON) {
437     events |= PORT_EV_RLSD;
438 
439     if (signal & PORT_DCD_ON) {
440       events |= PORT_EV_RLSDS;
441     }
442   }
443 
444   return p_port->ev_mask & events;
445 }
446 
447 /*******************************************************************************
448  *
449  * Function         port_flow_control_peer
450  *
451  * Description      Send flow control messages to the peer for both enabling
452  *                  and disabling flow control, for both credit-based and
453  *                  TS 07.10 flow control mechanisms.
454  *
455  * Returns          nothing
456  *
457  ******************************************************************************/
port_flow_control_peer(tPORT * p_port,bool enable,uint16_t count)458 void port_flow_control_peer(tPORT* p_port, bool enable, uint16_t count) {
459   if (!p_port->rfc.p_mcb) {
460     return;
461   }
462 
463   /* If using credit based flow control */
464   if (p_port->rfc.p_mcb->flow == PORT_FC_CREDIT) {
465     /* if want to enable flow from peer */
466     if (enable) {
467       /* update rx credits */
468       if (count > p_port->credit_rx) {
469         p_port->credit_rx = 0;
470       } else {
471         p_port->credit_rx -= count;
472       }
473 
474       /* If credit count is less than low credit watermark, and user */
475       /* did not force flow control, send a credit update */
476       /* There might be a special case when we just adjusted rx_max */
477       if ((p_port->credit_rx <= p_port->credit_rx_low) && !p_port->rx.user_fc &&
478           (p_port->credit_rx_max > p_port->credit_rx)) {
479         rfc_send_credit(p_port->rfc.p_mcb, p_port->dlci,
480                         (uint8_t)(p_port->credit_rx_max - p_port->credit_rx));
481 
482         p_port->credit_rx = p_port->credit_rx_max;
483 
484         p_port->rx.peer_fc = false;
485       }
486     } else {
487       /* else want to disable flow from peer */
488       /* if client registered data callback, just do what they want */
489       if (p_port->p_data_callback || p_port->p_data_co_callback) {
490         p_port->rx.peer_fc = true;
491       } else if (fixed_queue_length(p_port->rx.queue) >= p_port->credit_rx_max) {
492         /* if queue count reached credit rx max, set peer fc */
493         p_port->rx.peer_fc = true;
494       }
495     }
496   } else {
497     /* else using TS 07.10 flow control */
498     /* if want to enable flow from peer */
499     if (enable) {
500       /* If rfcomm suspended traffic from the peer based on the rx_queue_size */
501       /* check if it can be resumed now */
502       if (p_port->rx.peer_fc && (p_port->rx.queue_size < PORT_RX_LOW_WM) &&
503           (fixed_queue_length(p_port->rx.queue) < PORT_RX_BUF_LOW_WM)) {
504         p_port->rx.peer_fc = false;
505 
506         /* If user did not force flow control allow traffic now */
507         if (!p_port->rx.user_fc) {
508           RFCOMM_FlowReq(p_port->rfc.p_mcb, p_port->dlci, true);
509         }
510       }
511     } else {
512       /* else want to disable flow from peer */
513       /* if client registered data callback, just do what they want */
514       if (p_port->p_data_callback || p_port->p_data_co_callback) {
515         p_port->rx.peer_fc = true;
516         RFCOMM_FlowReq(p_port->rfc.p_mcb, p_port->dlci, false);
517       } else if (((p_port->rx.queue_size > PORT_RX_HIGH_WM) ||
518                   (fixed_queue_length(p_port->rx.queue) > PORT_RX_BUF_HIGH_WM)) &&
519                  !p_port->rx.peer_fc) {
520         /* Check the size of the rx queue.  If it exceeds certain */
521         /* level and flow control has not been sent to the peer do it now */
522         log::verbose("PORT_DataInd Data reached HW. Sending FC set.");
523 
524         p_port->rx.peer_fc = true;
525         RFCOMM_FlowReq(p_port->rfc.p_mcb, p_port->dlci, false);
526       }
527     }
528   }
529 }
530