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