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