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