• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /******************************************************************************
2  *
3  *  Copyright (C) 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 #include <base/logging.h>
25 #include <string.h>
26 
27 #include "osi/include/mutex.h"
28 
29 #include "bt_common.h"
30 #include "bt_target.h"
31 #include "btm_int.h"
32 #include "btu.h"
33 #include "l2cdefs.h"
34 #include "port_api.h"
35 #include "port_int.h"
36 #include "rfc_int.h"
37 #include "rfcdefs.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   tPORT* p_port = &rfc_cb.port.port[0];
65   uint8_t xx, yy;
66 
67   for (xx = 0, yy = rfc_cb.rfc.last_port + 1; xx < MAX_RFC_PORTS; xx++, yy++) {
68     if (yy >= MAX_RFC_PORTS) yy = 0;
69 
70     p_port = &rfc_cb.port.port[yy];
71     if (!p_port->in_use) {
72       memset(p_port, 0, sizeof(tPORT));
73 
74       p_port->in_use = true;
75       p_port->inx = yy + 1;
76 
77       /* During the open set default state for the port connection */
78       port_set_defaults(p_port);
79 
80       p_port->rfc.port_timer = alarm_new("rfcomm_port.port_timer");
81       rfc_cb.rfc.last_port = yy;
82 
83       p_port->dlci = dlci;
84       p_port->bd_addr = bd_addr;
85 
86       RFCOMM_TRACE_DEBUG("rfc_cb.port.port[%d]:%p allocated, last_port:%d", yy,
87                          p_port, rfc_cb.rfc.last_port);
88       VLOG(1) << __func__ << ": bd_addr:" << bd_addr;
89       return (p_port);
90     }
91   }
92 
93   /* If here, no free PORT found */
94   return (NULL);
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 = NULL;
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 = btm_get_max_packet_size(p_port->bd_addr);
147     if (packet_size == 0) {
148       /* something is very wrong */
149       RFCOMM_TRACE_WARNING("port_select_mtu bad packet size");
150       p_port->mtu = RFCOMM_DEFAULT_MTU;
151     } else {
152       /* We try to negotiate MTU that each packet can be split into whole
153       number of max packets.  For example if link is 1.2 max packet size is 339
154       bytes.
155       At first calculate how many whole packets it is.  MAX L2CAP is 1691 + 4
156       overhead.
157       1695, that will be 5 Dh5 packets.  Now maximum RFCOMM packet is
158       5 * 339 = 1695. Minus 4 bytes L2CAP header 1691.  Minus RFCOMM 6 bytes
159       header overhead 1685
160 
161       For EDR 2.0 packet size is 1027.  So we better send RFCOMM packet as 1
162       3DH5 packet
163       1 * 1027 = 1027.  Minus 4 bytes L2CAP header 1023.  Minus RFCOMM 6 bytes
164       header overhead 1017 */
165       if ((L2CAP_MTU_SIZE + L2CAP_PKT_OVERHEAD) >= packet_size) {
166         p_port->mtu = ((L2CAP_MTU_SIZE + L2CAP_PKT_OVERHEAD) / packet_size *
167                        packet_size) -
168                       RFCOMM_DATA_OVERHEAD - L2CAP_PKT_OVERHEAD;
169         RFCOMM_TRACE_DEBUG(
170             "port_select_mtu selected %d based on connection speed",
171             p_port->mtu);
172       } else {
173         p_port->mtu = L2CAP_MTU_SIZE - RFCOMM_DATA_OVERHEAD;
174         RFCOMM_TRACE_DEBUG(
175             "port_select_mtu selected %d based on l2cap PDU size", p_port->mtu);
176       }
177     }
178   } else {
179     RFCOMM_TRACE_DEBUG("port_select_mtu application selected %d", 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       "port_select_mtu credit_rx_max %d, credit_rx_low %d, rx_buf_critical %d",
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)) != NULL)
211     osi_free(p_buf);
212   p_port->rx.queue_size = 0;
213 
214   while ((p_buf = (BT_HDR*)fixed_queue_try_dequeue(p_port->tx.queue)) != NULL)
215     osi_free(p_buf);
216   p_port->tx.queue_size = 0;
217   mutex_global_unlock();
218 
219   alarm_cancel(p_port->rfc.port_timer);
220 
221   p_port->state = PORT_STATE_CLOSED;
222 
223   if (p_port->rfc.state == RFC_STATE_CLOSED) {
224     if (p_port->rfc.p_mcb) {
225       p_port->rfc.p_mcb->port_inx[p_port->dlci] = 0;
226 
227       /* If there are no more ports opened on this MCB release it */
228       rfc_check_mcb_active(p_port->rfc.p_mcb);
229     }
230 
231     rfc_port_timer_stop(p_port);
232 
233     mutex_global_lock();
234     fixed_queue_free(p_port->tx.queue, NULL);
235     p_port->tx.queue = NULL;
236     fixed_queue_free(p_port->rx.queue, NULL);
237     p_port->rx.queue = NULL;
238     mutex_global_unlock();
239 
240     if (p_port->keep_port_handle) {
241       RFCOMM_TRACE_DEBUG("%s Re-initialize handle: %d", __func__, p_port->inx);
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       tPORT_STATE user_port_pars = p_port->user_port_pars;
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_pars = user_port_pars;
254       p_port->mtu = p_port->keep_mtu;
255 
256       p_port->state = PORT_STATE_OPENING;
257       p_port->rfc.p_mcb = NULL;
258       if (p_port->is_server) p_port->dlci &= 0xfe;
259 
260       p_port->local_ctrl.modem_signal = p_port->default_signal_state;
261       p_port->bd_addr = RawAddress::kAny;
262     } else {
263       RFCOMM_TRACE_DEBUG("%s Clean-up handle: %d", __func__, p_port->inx);
264       alarm_free(p_port->rfc.port_timer);
265       memset(p_port, 0, sizeof(tPORT));
266     }
267   }
268 }
269 
270 /*******************************************************************************
271  *
272  * Function         port_find_mcb
273  *
274  * Description      This function checks if connection exists to device with
275  *                  the address.
276  *
277  ******************************************************************************/
port_find_mcb(const RawAddress & bd_addr)278 tRFC_MCB* port_find_mcb(const RawAddress& bd_addr) {
279   int i;
280 
281   for (i = 0; i < MAX_BD_CONNECTIONS; i++) {
282     if ((rfc_cb.port.rfc_mcb[i].state != RFC_MX_STATE_IDLE) &&
283         rfc_cb.port.rfc_mcb[i].bd_addr == bd_addr) {
284       /* Multiplexer channel found do not change anything */
285       VLOG(1) << __func__ << ": found bd_addr:" << bd_addr;
286       RFCOMM_TRACE_DEBUG(
287           "port_find_mcb: rfc_cb.port.rfc_mcb:index:%d, %p, lcid:%d", i,
288           &rfc_cb.port.rfc_mcb[i], rfc_cb.port.rfc_mcb[i].lcid);
289       return (&rfc_cb.port.rfc_mcb[i]);
290     }
291   }
292   VLOG(1) << __func__ << ": not found, bd_addr:" << bd_addr;
293   return (NULL);
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   uint8_t inx;
310 
311   if (!p_mcb) return (NULL);
312 
313   if (dlci > RFCOMM_MAX_DLCI) return (NULL);
314 
315   inx = p_mcb->port_inx[dlci];
316   if (inx == 0) {
317     RFCOMM_TRACE_DEBUG(
318         "port_find_mcb_dlci_port: p_mcb:%p, port_inx[dlci:%d] is 0", p_mcb,
319         dlci);
320     return (NULL);
321   } else
322     return (&rfc_cb.port.port[inx - 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   uint16_t i;
336   tPORT* p_port;
337 
338   for (i = 0; i < MAX_RFC_PORTS; i++) {
339     p_port = &rfc_cb.port.port[i];
340 
341     if (p_port->in_use && (p_port->rfc.p_mcb == NULL)) {
342       if (p_port->dlci == dlci) {
343         return (p_port);
344       } else if ((dlci & 0x01) && (p_port->dlci == (dlci - 1))) {
345         p_port->dlci++;
346         return (p_port);
347       }
348     }
349   }
350   return (NULL);
351 }
352 
353 /*******************************************************************************
354  *
355  * Function         port_find_port
356  *
357  * Description      Find port with DLCI, address
358  *
359  * Returns          Pointer to the PORT or NULL if not found
360  *
361  ******************************************************************************/
port_find_port(uint8_t dlci,const RawAddress & bd_addr)362 tPORT* port_find_port(uint8_t dlci, const RawAddress& bd_addr) {
363   uint16_t i;
364   tPORT* p_port;
365 
366   for (i = 0; i < MAX_RFC_PORTS; i++) {
367     p_port = &rfc_cb.port.port[i];
368     if (p_port->in_use && (p_port->dlci == dlci) &&
369         p_port->bd_addr == bd_addr) {
370       return (p_port);
371     }
372   }
373   return (NULL);
374 }
375 
376 /*******************************************************************************
377  *
378  * Function         port_flow_control_user
379  *
380  * Description      Check the current user flow control and if necessary return
381  *                  events to be send to the user based on the user's specified
382  *                  flow control type.
383  *
384  * Returns          event mask to be returned to the application
385  *
386  ******************************************************************************/
port_flow_control_user(tPORT * p_port)387 uint32_t port_flow_control_user(tPORT* p_port) {
388   uint32_t event = 0;
389 
390   /* Flow control to the user can be caused by flow controlling by the peer */
391   /* (FlowInd, or flow control by the peer RFCOMM (Fcon) or internally if */
392   /* tx_queue is full */
393   bool fc = p_port->tx.peer_fc || !p_port->rfc.p_mcb ||
394             !p_port->rfc.p_mcb->peer_ready ||
395             (p_port->tx.queue_size > PORT_TX_HIGH_WM) ||
396             (fixed_queue_length(p_port->tx.queue) > PORT_TX_BUF_HIGH_WM);
397 
398   if (p_port->tx.user_fc == fc) return (0);
399 
400   p_port->tx.user_fc = fc;
401 
402   if (fc)
403     event = PORT_EV_FC;
404   else
405     event = PORT_EV_FC | PORT_EV_FCS;
406 
407   return (event);
408 }
409 
410 /*******************************************************************************
411  *
412  * Function         port_get_signal_changes
413  *
414  * Description      Check modem signals that has been changed
415  *
416  * Returns          event mask to be returned to the application
417  *
418  ******************************************************************************/
port_get_signal_changes(tPORT * p_port,uint8_t old_signals,uint8_t signal)419 uint32_t port_get_signal_changes(tPORT* p_port, uint8_t old_signals,
420                                  uint8_t signal) {
421   uint8_t changed_signals = (signal ^ old_signals);
422   uint32_t events = 0;
423 
424   if (changed_signals & PORT_DTRDSR_ON) {
425     events |= PORT_EV_DSR;
426 
427     if (signal & PORT_DTRDSR_ON) events |= PORT_EV_DSRS;
428   }
429 
430   if (changed_signals & PORT_CTSRTS_ON) {
431     events |= PORT_EV_CTS;
432 
433     if (signal & PORT_CTSRTS_ON) events |= PORT_EV_CTSS;
434   }
435 
436   if (changed_signals & PORT_RING_ON) events |= PORT_EV_RING;
437 
438   if (changed_signals & PORT_DCD_ON) {
439     events |= PORT_EV_RLSD;
440 
441     if (signal & PORT_DCD_ON) events |= PORT_EV_RLSDS;
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) return;
460 
461   /* If using credit based flow control */
462   if (p_port->rfc.p_mcb->flow == PORT_FC_CREDIT) {
463     /* if want to enable flow from peer */
464     if (enable) {
465       /* update rx credits */
466       if (count > p_port->credit_rx) {
467         p_port->credit_rx = 0;
468       } else {
469         p_port->credit_rx -= count;
470       }
471 
472       /* If credit count is less than low credit watermark, and user */
473       /* did not force flow control, send a credit update */
474       /* There might be a special case when we just adjusted rx_max */
475       if ((p_port->credit_rx <= p_port->credit_rx_low) && !p_port->rx.user_fc &&
476           (p_port->credit_rx_max > p_port->credit_rx)) {
477         rfc_send_credit(p_port->rfc.p_mcb, p_port->dlci,
478                         (uint8_t)(p_port->credit_rx_max - p_port->credit_rx));
479 
480         p_port->credit_rx = p_port->credit_rx_max;
481 
482         p_port->rx.peer_fc = false;
483       }
484     }
485     /* else want to disable flow from peer */
486     else {
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       }
491       /* if queue count reached credit rx max, set peer fc */
492       else if (fixed_queue_length(p_port->rx.queue) >= p_port->credit_rx_max) {
493         p_port->rx.peer_fc = true;
494       }
495     }
496   }
497   /* else using TS 07.10 flow control */
498   else {
499     /* if want to enable flow from peer */
500     if (enable) {
501       /* If rfcomm suspended traffic from the peer based on the rx_queue_size */
502       /* check if it can be resumed now */
503       if (p_port->rx.peer_fc && (p_port->rx.queue_size < PORT_RX_LOW_WM) &&
504           (fixed_queue_length(p_port->rx.queue) < PORT_RX_BUF_LOW_WM)) {
505         p_port->rx.peer_fc = false;
506 
507         /* If user did not force flow control allow traffic now */
508         if (!p_port->rx.user_fc)
509           RFCOMM_FlowReq(p_port->rfc.p_mcb, p_port->dlci, true);
510       }
511     }
512     /* else want to disable flow from peer */
513     else {
514       /* if client registered data callback, just do what they want */
515       if (p_port->p_data_callback || p_port->p_data_co_callback) {
516         p_port->rx.peer_fc = true;
517         RFCOMM_FlowReq(p_port->rfc.p_mcb, p_port->dlci, false);
518       }
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       else if (((p_port->rx.queue_size > PORT_RX_HIGH_WM) ||
522                 (fixed_queue_length(p_port->rx.queue) > PORT_RX_BUF_HIGH_WM)) &&
523                !p_port->rx.peer_fc) {
524         RFCOMM_TRACE_EVENT("PORT_DataInd Data reached HW. Sending FC set.");
525 
526         p_port->rx.peer_fc = true;
527         RFCOMM_FlowReq(p_port->rfc.p_mcb, p_port->dlci, false);
528       }
529     }
530   }
531 }
532