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