1 /******************************************************************************
3 * Copyright (C) 1999-2012 Broadcom Corporation
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:
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 ******************************************************************************/
19 /******************************************************************************
21 * Port Emulation entity utilities
23 ******************************************************************************/
26 #include "bt_target.h"
36 static const tPORT_STATE default_port_pars = {
50 /*******************************************************************************
52 ** Function port_allocate_port
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
59 ** Returns Pointer to the PORT or NULL if not found
61 *******************************************************************************/
62 tPORT *port_allocate_port (UINT8 dlci, BD_ADDR bd_addr)
64 tPORT *p_port = &rfc_cb.port.port[0];
67 for (xx = 0, yy = rfc_cb.rfc.last_port + 1; xx < MAX_RFC_PORTS; xx++, yy++) {
68 if (yy >= MAX_RFC_PORTS) {
72 p_port = &rfc_cb.port.port[yy];
73 if (!p_port->in_use) {
74 memset (p_port, 0, sizeof (tPORT));
76 p_port->in_use = TRUE;
80 memcpy (p_port->bd_addr, bd_addr, BD_ADDR_LEN);
82 /* During the open set default state for the port connection */
83 port_set_defaults (p_port);
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]);
93 /* If here, no free PORT found */
98 /*******************************************************************************
100 ** Function port_set_defaults
102 ** Description Set defualt port parameters
105 *******************************************************************************/
106 void port_set_defaults (tPORT *p_port)
109 p_port->p_callback = NULL;
110 p_port->port_ctrl = 0;
112 p_port->line_status = 0;
113 p_port->rx_flag_ev_pending = FALSE;
114 p_port->peer_mtu = RFCOMM_DEFAULT_MTU;
116 p_port->user_port_pars = default_port_pars;
117 p_port->peer_port_pars = default_port_pars;
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 */
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));
130 /*******************************************************************************
132 ** Function port_select_mtu
134 ** Description Select MTU which will best serve connection from our
136 ** If our device is 1.2 or lower we calculate how many DH5s
137 ** fit into 1 RFCOMM buffer.
140 *******************************************************************************/
141 void port_select_mtu (tPORT *p_port)
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;
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
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);
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);
171 RFCOMM_TRACE_DEBUG ("port_select_mtu application selected %d", p_port->mtu);
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;
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;
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;
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);
190 /*******************************************************************************
192 ** Function port_release_port
194 ** Description Release port infor control block.
196 ** Returns Pointer to the PORT or NULL if not found
198 *******************************************************************************/
199 void port_release_port (tPORT *p_port)
203 tPORT_CALLBACK *p_port_cb;
204 tPORT_STATE user_port_pars;
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) {
212 p_port->rx.queue_size = 0;
214 while ((p_buf = (BT_HDR *)GKI_dequeue (&p_port->tx.queue)) != NULL) {
218 p_port->tx.queue_size = 0;
220 PORT_SCHEDULE_UNLOCK;
222 p_port->state = PORT_STATE_CLOSED;
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;
229 /* If there are no more ports opened on this MCB release it */
230 rfc_check_mcb_active (p_port->rfc.p_mcb);
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;
241 port_set_defaults(p_port);
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;
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;
254 p_port->local_ctrl.modem_signal = p_port->default_signal_state;
255 memcpy (p_port->bd_addr, BT_BD_ANY, BD_ADDR_LEN);
257 RFCOMM_TRACE_DEBUG ("port_release_port:Clean-up handle:%d", p_port->inx);
258 memset (p_port, 0, sizeof (tPORT));
264 /*******************************************************************************
266 ** Function port_find_mcb
268 ** Description This function checks if connection exists to device with
271 *******************************************************************************/
272 tRFC_MCB *port_find_mcb (BD_ADDR bd_addr)
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]);
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]);
293 /*******************************************************************************
295 ** Function port_find_mcb_dlci_port
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.
302 ** Returns Pointer to the PORT or NULL if not found
304 *******************************************************************************/
305 tPORT *port_find_mcb_dlci_port (tRFC_MCB *p_mcb, UINT8 dlci)
313 if (dlci > RFCOMM_MAX_DLCI) {
317 inx = p_mcb->port_inx[dlci];
319 RFCOMM_TRACE_DEBUG("port_find_mcb_dlci_port: p_mcb:%p, port_inx[dlci:%d] is 0", p_mcb, dlci);
322 return (&rfc_cb.port.port[inx - 1]);
327 /*******************************************************************************
329 ** Function port_find_dlci_port
331 ** Description Find port with DLCI not assigned to multiplexer channel
333 ** Returns Pointer to the PORT or NULL if not found
335 *******************************************************************************/
336 tPORT *port_find_dlci_port (UINT8 dlci)
341 for (i = 0; i < MAX_RFC_PORTS; i++) {
342 p_port = &rfc_cb.port.port[i];
344 if (p_port->in_use && (p_port->rfc.p_mcb == NULL)) {
345 if (p_port->dlci == dlci) {
347 } else if ((dlci & 0x01) && (p_port->dlci == (dlci - 1))) {
357 /*******************************************************************************
359 ** Function port_find_port
361 ** Description Find port with DLCI, BD_ADDR
363 ** Returns Pointer to the PORT or NULL if not found
365 *******************************************************************************/
366 tPORT *port_find_port (UINT8 dlci, BD_ADDR bd_addr)
371 for (i = 0; i < MAX_RFC_PORTS; i++) {
372 p_port = &rfc_cb.port.port[i];
374 && (p_port->dlci == dlci)
375 && !memcmp (p_port->bd_addr, bd_addr, BD_ADDR_LEN)) {
383 /*******************************************************************************
385 ** Function port_flow_control_user
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.
391 ** Returns event mask to be returned to the application
393 *******************************************************************************/
394 UINT32 port_flow_control_user (tPORT *p_port)
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);
407 if (p_port->tx.user_fc == fc) {
411 p_port->tx.user_fc = fc;
416 event = PORT_EV_FC | PORT_EV_FCS;
423 /*******************************************************************************
425 ** Function port_get_signal_changes
427 ** Description Check modem signals that has been changed
429 ** Returns event mask to be returned to the application
431 *******************************************************************************/
432 UINT32 port_get_signal_changes (tPORT *p_port, UINT8 old_signals, UINT8 signal)
434 UINT8 changed_signals = (signal ^ old_signals);
437 if (changed_signals & PORT_DTRDSR_ON) {
438 events |= PORT_EV_DSR;
440 if (signal & PORT_DTRDSR_ON) {
441 events |= PORT_EV_DSRS;
445 if (changed_signals & PORT_CTSRTS_ON) {
446 events |= PORT_EV_CTS;
448 if (signal & PORT_CTSRTS_ON) {
449 events |= PORT_EV_CTSS;
453 if (changed_signals & PORT_RING_ON) {
454 events |= PORT_EV_RING;
457 if (changed_signals & PORT_DCD_ON) {
458 events |= PORT_EV_RLSD;
460 if (signal & PORT_DCD_ON) {
461 events |= PORT_EV_RLSDS;
465 return (p_port->ev_mask & events);
468 /*******************************************************************************
470 ** Function port_flow_control_peer
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.
478 *******************************************************************************/
479 void port_flow_control_peer(tPORT *p_port, BOOLEAN enable, UINT16 count)
481 if (!p_port->rfc.p_mcb) {
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 */
489 /* update rx credits */
490 if (count > p_port->credit_rx) {
491 p_port->credit_rx = 0;
493 p_port->credit_rx -= count;
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));
505 p_port->credit_rx = p_port->credit_rx_max;
507 p_port->rx.peer_fc = FALSE;
510 /* else want to disable flow from peer */
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;
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;
522 /* else using TS 07.10 flow control */
524 /* if want to enable flow from peer */
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;
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);
539 /* else want to disable flow from peer */
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);
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.");
553 p_port->rx.peer_fc = TRUE;
554 RFCOMM_FlowReq (p_port->rfc.p_mcb, p_port->dlci, FALSE);