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