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_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 *******************************************************************************/
port_set_defaults(tPORT * p_port)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
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 *******************************************************************************/
port_select_mtu(tPORT * p_port)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 {
150 /* find packet size which connection supports */
151 packet_size = btm_get_max_packet_size (p_port->bd_addr);
152 if (packet_size == 0)
153 {
154 /* something is very wrong */
155 RFCOMM_TRACE_WARNING ("port_select_mtu bad packet size");
156 p_port->mtu = RFCOMM_DEFAULT_MTU;
157 }
158 else
159 {
160 /* We try to negotiate MTU that each packet can be split into whole
161 number of max packets. For example if link is 1.2 max packet size is 339 bytes.
162 At first calculate how many whole packets it is. MAX L2CAP is 1691 + 4 overhead.
163 1695, that will be 5 Dh5 packets. Now maximum RFCOMM packet is
164 5 * 339 = 1695. Minus 4 bytes L2CAP header 1691. Minus RFCOMM 6 bytes header overhead 1685
165
166 For EDR 2.0 packet size is 1027. So we better send RFCOMM packet as 1 3DH5 packet
167 1 * 1027 = 1027. Minus 4 bytes L2CAP header 1023. Minus RFCOMM 6 bytes header overhead 1017 */
168 if ((L2CAP_MTU_SIZE + L2CAP_PKT_OVERHEAD) >= packet_size)
169 {
170 p_port->mtu = ((L2CAP_MTU_SIZE + L2CAP_PKT_OVERHEAD) / packet_size * packet_size) - RFCOMM_DATA_OVERHEAD - L2CAP_PKT_OVERHEAD;
171 RFCOMM_TRACE_DEBUG ("port_select_mtu selected %d based on connection speed", p_port->mtu);
172 }
173 else
174 {
175 p_port->mtu = L2CAP_MTU_SIZE - RFCOMM_DATA_OVERHEAD;
176 RFCOMM_TRACE_DEBUG ("port_select_mtu selected %d based on l2cap PDU size", p_port->mtu);
177 }
178 }
179 }
180 else
181 {
182 RFCOMM_TRACE_DEBUG ("port_select_mtu application selected %d", p_port->mtu);
183 }
184 p_port->credit_rx_max = (PORT_RX_HIGH_WM / p_port->mtu);
185 if( p_port->credit_rx_max > PORT_RX_BUF_HIGH_WM )
186 p_port->credit_rx_max = PORT_RX_BUF_HIGH_WM;
187 p_port->credit_rx_low = (PORT_RX_LOW_WM / p_port->mtu);
188 if( p_port->credit_rx_low > PORT_RX_BUF_LOW_WM )
189 p_port->credit_rx_low = PORT_RX_BUF_LOW_WM;
190 p_port->rx_buf_critical = (PORT_RX_CRITICAL_WM / p_port->mtu);
191 if( p_port->rx_buf_critical > PORT_RX_BUF_CRITICAL_WM )
192 p_port->rx_buf_critical = PORT_RX_BUF_CRITICAL_WM;
193 RFCOMM_TRACE_DEBUG ("port_select_mtu credit_rx_max %d, credit_rx_low %d, rx_buf_critical %d",
194 p_port->credit_rx_max, p_port->credit_rx_low, p_port->rx_buf_critical);
195 }
196
197
198 /*******************************************************************************
199 **
200 ** Function port_release_port
201 **
202 ** Description Release port infor control block.
203 **
204 ** Returns Pointer to the PORT or NULL if not found
205 **
206 *******************************************************************************/
port_release_port(tPORT * p_port)207 void port_release_port (tPORT *p_port)
208 {
209 BT_HDR *p_buf;
210 UINT32 mask;
211 tPORT_CALLBACK *p_port_cb;
212 tPORT_STATE user_port_pars;
213
214 PORT_SCHEDULE_LOCK;
215 RFCOMM_TRACE_DEBUG("port_release_port, p_port:%p", p_port);
216 while ((p_buf = (BT_HDR *)GKI_dequeue (&p_port->rx.queue)) != NULL)
217 GKI_freebuf (p_buf);
218
219 p_port->rx.queue_size = 0;
220
221 while ((p_buf = (BT_HDR *)GKI_dequeue (&p_port->tx.queue)) != NULL)
222 GKI_freebuf (p_buf);
223
224 p_port->tx.queue_size = 0;
225
226 PORT_SCHEDULE_UNLOCK;
227
228 p_port->state = PORT_STATE_CLOSED;
229
230 if (p_port->rfc.state == RFC_STATE_CLOSED)
231 {
232 RFCOMM_TRACE_DEBUG ("rfc_port_closed DONE");
233 if (p_port->rfc.p_mcb)
234 {
235 p_port->rfc.p_mcb->port_inx[p_port->dlci] = 0;
236
237 /* If there are no more ports opened on this MCB release it */
238 rfc_check_mcb_active (p_port->rfc.p_mcb);
239 }
240 rfc_port_timer_stop (p_port);
241 RFCOMM_TRACE_DEBUG ("port_release_port:p_port->keep_port_handle:%d", p_port->keep_port_handle);
242 if( p_port->keep_port_handle )
243 {
244 RFCOMM_TRACE_DEBUG ("port_release_port:Initialize handle:%d", p_port->inx);
245 /* save event mask and callback */
246 mask = p_port->ev_mask;
247 p_port_cb = p_port->p_callback;
248 user_port_pars = p_port->user_port_pars;
249
250 port_set_defaults(p_port);
251 /* restore */
252 p_port->ev_mask = mask;
253 p_port->p_callback = p_port_cb;
254 p_port->user_port_pars = user_port_pars;
255 p_port->mtu = p_port->keep_mtu;
256
257 p_port->state = PORT_STATE_OPENING;
258 p_port->rfc.p_mcb = NULL;
259 if(p_port->is_server)
260 p_port->dlci &= 0xfe;
261
262 p_port->local_ctrl.modem_signal = p_port->default_signal_state;
263 memcpy (p_port->bd_addr, BT_BD_ANY, BD_ADDR_LEN);
264 }
265 else
266 {
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 *******************************************************************************/
port_find_mcb(BD_ADDR bd_addr)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 {
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 {
291 /* Multiplexer channel found do not change anything */
292 RFCOMM_TRACE_DEBUG("port_find_mcb: found bd_addr:%02x:%02x:%02x:%02x:%02x:%02x",
293 bd_addr[0], bd_addr[1], bd_addr[2], bd_addr[3], bd_addr[4], bd_addr[5]);
294 RFCOMM_TRACE_DEBUG("port_find_mcb: rfc_cb.port.rfc_mcb:index:%d, %p, lcid:%d",
295 i, &rfc_cb.port.rfc_mcb[i], rfc_cb.port.rfc_mcb[i].lcid);
296 return (&rfc_cb.port.rfc_mcb[i]);
297 }
298 }
299 RFCOMM_TRACE_DEBUG("port_find_mcb: not found, bd_addr:%02x:%02x:%02x:%02x:%02x:%02x",
300 bd_addr[0], bd_addr[1], bd_addr[2], bd_addr[3], bd_addr[4], bd_addr[5]);
301 return (NULL);
302 }
303
304
305 /*******************************************************************************
306 **
307 ** Function port_find_mcb_dlci_port
308 **
309 ** Description Find port on the multiplexer channel based on DLCI. If
310 ** this port with DLCI not found try to use even DLCI. This
311 ** is for the case when client is establishing connection on
312 ** none-initiator MCB.
313 **
314 ** Returns Pointer to the PORT or NULL if not found
315 **
316 *******************************************************************************/
port_find_mcb_dlci_port(tRFC_MCB * p_mcb,UINT8 dlci)317 tPORT *port_find_mcb_dlci_port (tRFC_MCB *p_mcb, UINT8 dlci)
318 {
319 UINT8 inx;
320
321 if (!p_mcb)
322 return (NULL);
323
324 if (dlci > RFCOMM_MAX_DLCI)
325 return (NULL);
326
327 inx = p_mcb->port_inx[dlci];
328 if (inx == 0)
329 {
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 }
333 else
334 return (&rfc_cb.port.port[inx - 1]);
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 *******************************************************************************/
port_find_dlci_port(UINT8 dlci)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 {
354 p_port = &rfc_cb.port.port[i];
355
356 if (p_port->in_use && (p_port->rfc.p_mcb == NULL))
357 {
358 if (p_port->dlci == dlci)
359 {
360 return (p_port);
361 }
362 else if ((dlci & 0x01) && (p_port->dlci == (dlci - 1)))
363 {
364 p_port->dlci++;
365 return (p_port);
366 }
367 }
368 }
369 return (NULL);
370 }
371
372
373 /*******************************************************************************
374 **
375 ** Function port_find_port
376 **
377 ** Description Find port with DLCI, BD_ADDR
378 **
379 ** Returns Pointer to the PORT or NULL if not found
380 **
381 *******************************************************************************/
port_find_port(UINT8 dlci,BD_ADDR bd_addr)382 tPORT *port_find_port (UINT8 dlci, BD_ADDR bd_addr)
383 {
384 UINT16 i;
385 tPORT *p_port;
386
387 for (i = 0; i < MAX_RFC_PORTS; i++)
388 {
389 p_port = &rfc_cb.port.port[i];
390 if (p_port->in_use
391 && (p_port->dlci == dlci)
392 && !memcmp (p_port->bd_addr, bd_addr, BD_ADDR_LEN))
393 {
394 return (p_port);
395 }
396 }
397 return (NULL);
398 }
399
400
401 /*******************************************************************************
402 **
403 ** Function port_flow_control_user
404 **
405 ** Description Check the current user flow control and if necessary return
406 ** events to be send to the user based on the user's specified
407 ** flow control type.
408 **
409 ** Returns event mask to be returned to the application
410 **
411 *******************************************************************************/
port_flow_control_user(tPORT * p_port)412 UINT32 port_flow_control_user (tPORT *p_port)
413 {
414 UINT32 event = 0;
415
416 /* Flow control to the user can be caused by flow controlling by the peer */
417 /* (FlowInd, or flow control by the peer RFCOMM (Fcon) or internally if */
418 /* tx_queue is full */
419 BOOLEAN fc = p_port->tx.peer_fc
420 || !p_port->rfc.p_mcb
421 || !p_port->rfc.p_mcb->peer_ready
422 || (p_port->tx.queue_size > PORT_TX_HIGH_WM)
423 || (p_port->tx.queue.count > PORT_TX_BUF_HIGH_WM);
424
425 if (p_port->tx.user_fc == fc)
426 return (0);
427
428 p_port->tx.user_fc = fc;
429
430 if (fc)
431 event = PORT_EV_FC;
432 else
433 event = PORT_EV_FC | PORT_EV_FCS;
434
435 return (event);
436 }
437
438
439 /*******************************************************************************
440 **
441 ** Function port_get_signal_changes
442 **
443 ** Description Check modem signals that has been changed
444 **
445 ** Returns event mask to be returned to the application
446 **
447 *******************************************************************************/
port_get_signal_changes(tPORT * p_port,UINT8 old_signals,UINT8 signal)448 UINT32 port_get_signal_changes (tPORT *p_port, UINT8 old_signals, UINT8 signal)
449 {
450 UINT8 changed_signals = (signal ^ old_signals);
451 UINT32 events = 0;
452
453 if (changed_signals & PORT_DTRDSR_ON)
454 {
455 events |= PORT_EV_DSR;
456
457 if (signal & PORT_DTRDSR_ON)
458 events |= PORT_EV_DSRS;
459 }
460
461 if (changed_signals & PORT_CTSRTS_ON)
462 {
463 events |= PORT_EV_CTS;
464
465 if (signal & PORT_CTSRTS_ON)
466 events |= PORT_EV_CTSS;
467 }
468
469 if (changed_signals & PORT_RING_ON)
470 events |= PORT_EV_RING;
471
472 if (changed_signals & PORT_DCD_ON)
473 {
474 events |= PORT_EV_RLSD;
475
476 if (signal & PORT_DCD_ON)
477 events |= PORT_EV_RLSDS;
478 }
479
480 return (p_port->ev_mask & events);
481 }
482
483 /*******************************************************************************
484 **
485 ** Function port_flow_control_peer
486 **
487 ** Description Send flow control messages to the peer for both enabling
488 ** and disabling flow control, for both credit-based and
489 ** TS 07.10 flow control mechanisms.
490 **
491 ** Returns nothing
492 **
493 *******************************************************************************/
port_flow_control_peer(tPORT * p_port,BOOLEAN enable,UINT16 count)494 void port_flow_control_peer(tPORT *p_port, BOOLEAN enable, UINT16 count)
495 {
496 if (!p_port->rfc.p_mcb)
497 return;
498
499 /* If using credit based flow control */
500 if (p_port->rfc.p_mcb->flow == PORT_FC_CREDIT)
501 {
502 /* if want to enable flow from peer */
503 if (enable)
504 {
505 /* update rx credits */
506 if (count > p_port->credit_rx)
507 {
508 p_port->credit_rx = 0;
509 }
510 else
511 {
512 p_port->credit_rx -= count;
513 }
514
515 /* If credit count is less than low credit watermark, and user */
516 /* did not force flow control, send a credit update */
517 /* There might be a special case when we just adjusted rx_max */
518 if ((p_port->credit_rx <= p_port->credit_rx_low)
519 && !p_port->rx.user_fc
520 && (p_port->credit_rx_max > p_port->credit_rx))
521 {
522 rfc_send_credit(p_port->rfc.p_mcb, p_port->dlci,
523 (UINT8) (p_port->credit_rx_max - p_port->credit_rx));
524
525 p_port->credit_rx = p_port->credit_rx_max;
526
527 p_port->rx.peer_fc = FALSE;
528 }
529 }
530 /* else want to disable flow from peer */
531 else
532 {
533 /* if client registered data callback, just do what they want */
534 if (p_port->p_data_callback || p_port->p_data_co_callback)
535 {
536 p_port->rx.peer_fc = TRUE;
537 }
538 /* if queue count reached credit rx max, set peer fc */
539 else if (p_port->rx.queue.count >= p_port->credit_rx_max)
540 {
541 p_port->rx.peer_fc = TRUE;
542 }
543 }
544 }
545 /* else using TS 07.10 flow control */
546 else
547 {
548 /* if want to enable flow from peer */
549 if (enable)
550 {
551 /* If rfcomm suspended traffic from the peer based on the rx_queue_size */
552 /* check if it can be resumed now */
553 if (p_port->rx.peer_fc
554 && (p_port->rx.queue_size < PORT_RX_LOW_WM)
555 && (p_port->rx.queue.count < PORT_RX_BUF_LOW_WM))
556 {
557 p_port->rx.peer_fc = FALSE;
558
559 /* If user did not force flow control allow traffic now */
560 if (!p_port->rx.user_fc)
561 RFCOMM_FlowReq (p_port->rfc.p_mcb, p_port->dlci, TRUE);
562 }
563 }
564 /* else want to disable flow from peer */
565 else
566 {
567 /* if client registered data callback, just do what they want */
568 if (p_port->p_data_callback || p_port->p_data_co_callback)
569 {
570 p_port->rx.peer_fc = TRUE;
571 RFCOMM_FlowReq (p_port->rfc.p_mcb, p_port->dlci, FALSE);
572 }
573 /* Check the size of the rx queue. If it exceeds certain */
574 /* level and flow control has not been sent to the peer do it now */
575 else if ( ((p_port->rx.queue_size > PORT_RX_HIGH_WM)
576 || (p_port->rx.queue.count > PORT_RX_BUF_HIGH_WM))
577 && !p_port->rx.peer_fc)
578 {
579 RFCOMM_TRACE_EVENT ("PORT_DataInd Data reached HW. Sending FC set.");
580
581 p_port->rx.peer_fc = TRUE;
582 RFCOMM_FlowReq (p_port->rfc.p_mcb, p_port->dlci, FALSE);
583 }
584 }
585 }
586 }
587
588