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