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