]> granicus.if.org Git - esp-idf/blob - components/bt/bluedroid/stack/rfcomm/port_utils.c
Merge branch 'bugfix/int_wdt_in_ocd_mode' into 'master'
[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 "rfcdefs.h"
28 #include "port_api.h"
29 #include "port_int.h"
30 #include "rfc_int.h"
31 #include "l2cdefs.h"
32 #include "btm_int.h"
33 #include "btu.h"
34 #include "mutex.h"
35 #include "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 *******************************************************************************/
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 *******************************************************************************/
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(SIZE_MAX);
132     p_port->rx.queue = fixed_queue_new(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 *******************************************************************************/
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 *******************************************************************************/
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     while ((p_buf = (BT_HDR *)fixed_queue_try_dequeue(p_port->rx.queue)) != NULL) {
214         osi_free (p_buf);
215     }
216
217     p_port->rx.queue_size = 0;
218
219     while ((p_buf = (BT_HDR *)fixed_queue_try_dequeue(p_port->tx.queue)) != NULL) {
220         osi_free (p_buf);
221     }
222
223     p_port->tx.queue_size = 0;
224
225     osi_mutex_global_unlock();
226
227     p_port->state = PORT_STATE_CLOSED;
228
229     if (p_port->rfc.state == RFC_STATE_CLOSED) {
230         RFCOMM_TRACE_DEBUG ("rfc_port_closed DONE");
231         if (p_port->rfc.p_mcb) {
232             p_port->rfc.p_mcb->port_inx[p_port->dlci] = 0;
233
234             /* If there are no more ports opened on this MCB release it */
235             rfc_check_mcb_active (p_port->rfc.p_mcb);
236         }
237         rfc_port_timer_stop (p_port);
238         fixed_queue_free(p_port->tx.queue, NULL);
239         p_port->tx.queue = NULL;
240         fixed_queue_free(p_port->rx.queue, NULL);
241         p_port->rx.queue = NULL;
242                 
243         RFCOMM_TRACE_DEBUG ("port_release_port:p_port->keep_port_handle:%d", p_port->keep_port_handle);
244         if ( p_port->keep_port_handle ) {
245             RFCOMM_TRACE_DEBUG ("port_release_port:Initialize handle:%d", p_port->inx);
246             /* save event mask and callback */
247             mask = p_port->ev_mask;
248             p_port_cb = p_port->p_callback;
249             user_port_pars = p_port->user_port_pars;
250
251             port_set_defaults(p_port);
252             /* restore */
253             p_port->ev_mask         = mask;
254             p_port->p_callback      = p_port_cb;
255             p_port->user_port_pars  = user_port_pars;
256             p_port->mtu             = p_port->keep_mtu;
257
258             p_port->state           = PORT_STATE_OPENING;
259             p_port->rfc.p_mcb       = NULL;
260             if (p_port->is_server) {
261                 p_port->dlci       &= 0xfe;
262             }
263
264             p_port->local_ctrl.modem_signal = p_port->default_signal_state;
265             memcpy (p_port->bd_addr, BT_BD_ANY, BD_ADDR_LEN);
266         } else {
267             RFCOMM_TRACE_DEBUG ("port_release_port:Clean-up handle:%d", p_port->inx);
268             memset (p_port, 0, sizeof (tPORT));
269         }
270     }
271 }
272
273
274 /*******************************************************************************
275 **
276 ** Function         port_find_mcb
277 **
278 ** Description      This function checks if connection exists to device with
279 **                  the BD_ADDR.
280 **
281 *******************************************************************************/
282 tRFC_MCB *port_find_mcb (BD_ADDR bd_addr)
283 {
284     int      i;
285
286     for (i = 0; i < MAX_BD_CONNECTIONS; i++) {
287         if ((rfc_cb.port.rfc_mcb[i].state != RFC_MX_STATE_IDLE)
288                 && !memcmp (rfc_cb.port.rfc_mcb[i].bd_addr, bd_addr, BD_ADDR_LEN)) {
289             /* Multiplexer channel found do not change anything */
290             RFCOMM_TRACE_DEBUG("port_find_mcb: found  bd_addr:%02x:%02x:%02x:%02x:%02x:%02x",
291                                bd_addr[0], bd_addr[1], bd_addr[2], bd_addr[3], bd_addr[4], bd_addr[5]);
292             RFCOMM_TRACE_DEBUG("port_find_mcb: rfc_cb.port.rfc_mcb:index:%d, %p, lcid:%d",
293                                i, &rfc_cb.port.rfc_mcb[i], rfc_cb.port.rfc_mcb[i].lcid);
294             return (&rfc_cb.port.rfc_mcb[i]);
295         }
296     }
297     RFCOMM_TRACE_DEBUG("port_find_mcb: not 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     return (NULL);
300 }
301
302
303 /*******************************************************************************
304 **
305 ** Function         port_find_mcb_dlci_port
306 **
307 ** Description      Find port on the multiplexer channel based on DLCI.  If
308 **                  this port with DLCI not found try to use even DLCI.  This
309 **                  is for the case when client is establishing connection on
310 **                  none-initiator MCB.
311 **
312 ** Returns          Pointer to the PORT or NULL if not found
313 **
314 *******************************************************************************/
315 tPORT *port_find_mcb_dlci_port (tRFC_MCB *p_mcb, UINT8 dlci)
316 {
317     UINT8 inx;
318
319     if (!p_mcb) {
320         return (NULL);
321     }
322
323     if (dlci > RFCOMM_MAX_DLCI) {
324         return (NULL);
325     }
326
327     inx = p_mcb->port_inx[dlci];
328     if (inx == 0) {
329         RFCOMM_TRACE_DEBUG("port_find_mcb_dlci_port: p_mcb:%p, port_inx[dlci:%d] is 0", p_mcb, dlci);
330         return (NULL);
331     } else {
332         return (&rfc_cb.port.port[inx - 1]);
333     }
334 }
335
336
337 /*******************************************************************************
338 **
339 ** Function         port_find_dlci_port
340 **
341 ** Description      Find port with DLCI not assigned to multiplexer channel
342 **
343 ** Returns          Pointer to the PORT or NULL if not found
344 **
345 *******************************************************************************/
346 tPORT *port_find_dlci_port (UINT8 dlci)
347 {
348     UINT16 i;
349     tPORT  *p_port;
350
351     for (i = 0; i < MAX_RFC_PORTS; i++) {
352         p_port = &rfc_cb.port.port[i];
353
354         if (p_port->in_use && (p_port->rfc.p_mcb == NULL)) {
355             if (p_port->dlci == dlci) {
356                 return (p_port);
357             } else if ((dlci & 0x01) && (p_port->dlci == (dlci - 1))) {
358                 p_port->dlci++;
359                 return (p_port);
360             }
361         }
362     }
363     return (NULL);
364 }
365
366
367 /*******************************************************************************
368 **
369 ** Function         port_find_port
370 **
371 ** Description      Find port with DLCI, BD_ADDR
372 **
373 ** Returns          Pointer to the PORT or NULL if not found
374 **
375 *******************************************************************************/
376 tPORT *port_find_port (UINT8 dlci, BD_ADDR bd_addr)
377 {
378     UINT16 i;
379     tPORT  *p_port;
380
381     for (i = 0; i < MAX_RFC_PORTS; i++) {
382         p_port = &rfc_cb.port.port[i];
383         if (p_port->in_use
384                 && (p_port->dlci == dlci)
385                 && !memcmp (p_port->bd_addr, bd_addr, BD_ADDR_LEN)) {
386             return (p_port);
387         }
388     }
389     return (NULL);
390 }
391
392
393 /*******************************************************************************
394 **
395 ** Function         port_flow_control_user
396 **
397 ** Description      Check the current user flow control and if necessary return
398 **                  events to be send to the user based on the user's specified
399 **                  flow control type.
400 **
401 ** Returns          event mask to be returned to the application
402 **
403 *******************************************************************************/
404 UINT32 port_flow_control_user (tPORT *p_port)
405 {
406     UINT32 event = 0;
407
408     /* Flow control to the user can be caused by flow controlling by the peer */
409     /* (FlowInd, or flow control by the peer RFCOMM (Fcon) or internally if */
410     /* tx_queue is full */
411     BOOLEAN fc = p_port->tx.peer_fc
412                  || !p_port->rfc.p_mcb
413                  || !p_port->rfc.p_mcb->peer_ready
414                  || (p_port->tx.queue_size > PORT_TX_HIGH_WM)
415                  || (fixed_queue_length(p_port->tx.queue) > PORT_TX_BUF_HIGH_WM);
416
417     if (p_port->tx.user_fc == fc) {
418         return (0);
419     }
420
421     p_port->tx.user_fc = fc;
422
423     if (fc) {
424         event = PORT_EV_FC;
425     } else {
426         event = PORT_EV_FC | PORT_EV_FCS;
427     }
428
429     return (event);
430 }
431
432
433 /*******************************************************************************
434 **
435 ** Function         port_get_signal_changes
436 **
437 ** Description      Check modem signals that has been changed
438 **
439 ** Returns          event mask to be returned to the application
440 **
441 *******************************************************************************/
442 UINT32 port_get_signal_changes (tPORT *p_port, UINT8 old_signals, UINT8 signal)
443 {
444     UINT8  changed_signals = (signal ^ old_signals);
445     UINT32 events = 0;
446
447     if (changed_signals & PORT_DTRDSR_ON) {
448         events |= PORT_EV_DSR;
449
450         if (signal & PORT_DTRDSR_ON) {
451             events |= PORT_EV_DSRS;
452         }
453     }
454
455     if (changed_signals & PORT_CTSRTS_ON) {
456         events |= PORT_EV_CTS;
457
458         if (signal & PORT_CTSRTS_ON) {
459             events |= PORT_EV_CTSS;
460         }
461     }
462
463     if (changed_signals & PORT_RING_ON) {
464         events |= PORT_EV_RING;
465     }
466
467     if (changed_signals & PORT_DCD_ON) {
468         events |= PORT_EV_RLSD;
469
470         if (signal & PORT_DCD_ON) {
471             events |= PORT_EV_RLSDS;
472         }
473     }
474
475     return (p_port->ev_mask & events);
476 }
477
478 /*******************************************************************************
479 **
480 ** Function         port_flow_control_peer
481 **
482 ** Description      Send flow control messages to the peer for both enabling
483 **                  and disabling flow control, for both credit-based and
484 **                  TS 07.10 flow control mechanisms.
485 **
486 ** Returns          nothing
487 **
488 *******************************************************************************/
489 void port_flow_control_peer(tPORT *p_port, BOOLEAN enable, UINT16 count)
490 {
491     if (!p_port->rfc.p_mcb) {
492         return;
493     }
494
495     /* If using credit based flow control */
496     if (p_port->rfc.p_mcb->flow == PORT_FC_CREDIT) {
497         /* if want to enable flow from peer */
498         if (enable) {
499             /* update rx credits */
500             if (count > p_port->credit_rx) {
501                 p_port->credit_rx = 0;
502             } else {
503                 p_port->credit_rx -= count;
504             }
505
506             /* If credit count is less than low credit watermark, and user */
507             /* did not force flow control, send a credit update */
508             /* There might be a special case when we just adjusted rx_max */
509             if ((p_port->credit_rx <= p_port->credit_rx_low)
510                     && !p_port->rx.user_fc
511                     && (p_port->credit_rx_max > p_port->credit_rx)) {
512                 rfc_send_credit(p_port->rfc.p_mcb, p_port->dlci,
513                                 (UINT8) (p_port->credit_rx_max - p_port->credit_rx));
514
515                 p_port->credit_rx = p_port->credit_rx_max;
516
517                 p_port->rx.peer_fc = FALSE;
518             }
519         }
520         /* else want to disable flow from peer */
521         else {
522             /* if client registered data callback, just do what they want */
523             if (p_port->p_data_callback || p_port->p_data_co_callback) {
524                 p_port->rx.peer_fc = TRUE;
525             }
526             /* if queue count reached credit rx max, set peer fc */
527             else if (fixed_queue_length(p_port->rx.queue) >= p_port->credit_rx_max) {
528                 p_port->rx.peer_fc = TRUE;
529             }
530         }
531     }
532     /* else using TS 07.10 flow control */
533     else {
534         /* if want to enable flow from peer */
535         if (enable) {
536             /* If rfcomm suspended traffic from the peer based on the rx_queue_size */
537             /* check if it can be resumed now */
538             if (p_port->rx.peer_fc
539                     && (p_port->rx.queue_size < PORT_RX_LOW_WM)
540                     && (fixed_queue_length(p_port->rx.queue) < PORT_RX_BUF_LOW_WM)) {
541                 p_port->rx.peer_fc = FALSE;
542
543                 /* If user did not force flow control allow traffic now */
544                 if (!p_port->rx.user_fc) {
545                     RFCOMM_FlowReq (p_port->rfc.p_mcb, p_port->dlci, TRUE);
546                 }
547             }
548         }
549         /* else want to disable flow from peer */
550         else {
551             /* if client registered data callback, just do what they want */
552             if (p_port->p_data_callback || p_port->p_data_co_callback) {
553                 p_port->rx.peer_fc = TRUE;
554                 RFCOMM_FlowReq (p_port->rfc.p_mcb, p_port->dlci, FALSE);
555             }
556             /* Check the size of the rx queue.  If it exceeds certain */
557             /* level and flow control has not been sent to the peer do it now */
558             else if ( ((p_port->rx.queue_size > PORT_RX_HIGH_WM)
559                       || (fixed_queue_length(p_port->rx.queue) > PORT_RX_BUF_HIGH_WM))
560                       && !p_port->rx.peer_fc) {
561                 RFCOMM_TRACE_EVENT ("PORT_DataInd Data reached HW. Sending FC set.");
562
563                 p_port->rx.peer_fc = TRUE;
564                 RFCOMM_FlowReq (p_port->rfc.p_mcb, p_port->dlci, FALSE);
565             }
566         }
567     }
568 }
569
570
571 #endif ///(defined RFCOMM_INCLUDED && RFCOMM_INCLUDED == TRUE)