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"
35 static const tPORT_STATE default_port_pars = {
49 /*******************************************************************************
51 ** Function port_allocate_port
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
58 ** Returns Pointer to the PORT or NULL if not found
60 *******************************************************************************/
61 tPORT *port_allocate_port (UINT8 dlci, BD_ADDR bd_addr)
63 tPORT *p_port = &rfc_cb.port.port[0];
66 for (xx = 0, yy = rfc_cb.rfc.last_port + 1; xx < MAX_RFC_PORTS; xx++, yy++) {
67 if (yy >= MAX_RFC_PORTS) {
71 p_port = &rfc_cb.port.port[yy];
72 if (!p_port->in_use) {
73 memset (p_port, 0, sizeof (tPORT));
75 p_port->in_use = TRUE;
79 memcpy (p_port->bd_addr, bd_addr, BD_ADDR_LEN);
81 /* During the open set default state for the port connection */
82 port_set_defaults (p_port);
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]);
92 /* If here, no free PORT found */
97 /*******************************************************************************
99 ** Function port_set_defaults
101 ** Description Set defualt port parameters
104 *******************************************************************************/
105 void port_set_defaults (tPORT *p_port)
108 p_port->p_callback = NULL;
109 p_port->port_ctrl = 0;
111 p_port->line_status = 0;
112 p_port->rx_flag_ev_pending = FALSE;
113 p_port->peer_mtu = RFCOMM_DEFAULT_MTU;
115 p_port->user_port_pars = default_port_pars;
116 p_port->peer_port_pars = default_port_pars;
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 */
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));
128 p_port->tx.queue = fixed_queue_new(SIZE_MAX);
129 p_port->rx.queue = fixed_queue_new(SIZE_MAX);
132 /*******************************************************************************
134 ** Function port_select_mtu
136 ** Description Select MTU which will best serve connection from our
138 ** If our device is 1.2 or lower we calculate how many DH5s
139 ** fit into 1 RFCOMM buffer.
142 *******************************************************************************/
143 void port_select_mtu (tPORT *p_port)
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;
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
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);
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);
173 RFCOMM_TRACE_DEBUG ("port_select_mtu application selected %d", p_port->mtu);
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;
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;
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;
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);
192 /*******************************************************************************
194 ** Function port_release_port
196 ** Description Release port infor control block.
198 ** Returns Pointer to the PORT or NULL if not found
200 *******************************************************************************/
201 void port_release_port (tPORT *p_port)
205 tPORT_CALLBACK *p_port_cb;
206 tPORT_STATE user_port_pars;
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) {
214 p_port->rx.queue_size = 0;
216 while ((p_buf = (BT_HDR *)fixed_queue_try_dequeue(p_port->tx.queue)) != NULL) {
220 p_port->tx.queue_size = 0;
222 osi_mutex_global_unlock();
224 p_port->state = PORT_STATE_CLOSED;
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;
231 /* If there are no more ports opened on this MCB release it */
232 rfc_check_mcb_active (p_port->rfc.p_mcb);
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;
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;
248 port_set_defaults(p_port);
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;
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;
261 p_port->local_ctrl.modem_signal = p_port->default_signal_state;
262 memcpy (p_port->bd_addr, BT_BD_ANY, BD_ADDR_LEN);
264 RFCOMM_TRACE_DEBUG ("port_release_port:Clean-up handle:%d", p_port->inx);
265 memset (p_port, 0, sizeof (tPORT));
271 /*******************************************************************************
273 ** Function port_find_mcb
275 ** Description This function checks if connection exists to device with
278 *******************************************************************************/
279 tRFC_MCB *port_find_mcb (BD_ADDR bd_addr)
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]);
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]);
300 /*******************************************************************************
302 ** Function port_find_mcb_dlci_port
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.
309 ** Returns Pointer to the PORT or NULL if not found
311 *******************************************************************************/
312 tPORT *port_find_mcb_dlci_port (tRFC_MCB *p_mcb, UINT8 dlci)
320 if (dlci > RFCOMM_MAX_DLCI) {
324 inx = p_mcb->port_inx[dlci];
326 RFCOMM_TRACE_DEBUG("port_find_mcb_dlci_port: p_mcb:%p, port_inx[dlci:%d] is 0", p_mcb, dlci);
329 return (&rfc_cb.port.port[inx - 1]);
334 /*******************************************************************************
336 ** Function port_find_dlci_port
338 ** Description Find port with DLCI not assigned to multiplexer channel
340 ** Returns Pointer to the PORT or NULL if not found
342 *******************************************************************************/
343 tPORT *port_find_dlci_port (UINT8 dlci)
348 for (i = 0; i < MAX_RFC_PORTS; i++) {
349 p_port = &rfc_cb.port.port[i];
351 if (p_port->in_use && (p_port->rfc.p_mcb == NULL)) {
352 if (p_port->dlci == dlci) {
354 } else if ((dlci & 0x01) && (p_port->dlci == (dlci - 1))) {
364 /*******************************************************************************
366 ** Function port_find_port
368 ** Description Find port with DLCI, BD_ADDR
370 ** Returns Pointer to the PORT or NULL if not found
372 *******************************************************************************/
373 tPORT *port_find_port (UINT8 dlci, BD_ADDR bd_addr)
378 for (i = 0; i < MAX_RFC_PORTS; i++) {
379 p_port = &rfc_cb.port.port[i];
381 && (p_port->dlci == dlci)
382 && !memcmp (p_port->bd_addr, bd_addr, BD_ADDR_LEN)) {
390 /*******************************************************************************
392 ** Function port_flow_control_user
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.
398 ** Returns event mask to be returned to the application
400 *******************************************************************************/
401 UINT32 port_flow_control_user (tPORT *p_port)
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);
414 if (p_port->tx.user_fc == fc) {
418 p_port->tx.user_fc = fc;
423 event = PORT_EV_FC | PORT_EV_FCS;
430 /*******************************************************************************
432 ** Function port_get_signal_changes
434 ** Description Check modem signals that has been changed
436 ** Returns event mask to be returned to the application
438 *******************************************************************************/
439 UINT32 port_get_signal_changes (tPORT *p_port, UINT8 old_signals, UINT8 signal)
441 UINT8 changed_signals = (signal ^ old_signals);
444 if (changed_signals & PORT_DTRDSR_ON) {
445 events |= PORT_EV_DSR;
447 if (signal & PORT_DTRDSR_ON) {
448 events |= PORT_EV_DSRS;
452 if (changed_signals & PORT_CTSRTS_ON) {
453 events |= PORT_EV_CTS;
455 if (signal & PORT_CTSRTS_ON) {
456 events |= PORT_EV_CTSS;
460 if (changed_signals & PORT_RING_ON) {
461 events |= PORT_EV_RING;
464 if (changed_signals & PORT_DCD_ON) {
465 events |= PORT_EV_RLSD;
467 if (signal & PORT_DCD_ON) {
468 events |= PORT_EV_RLSDS;
472 return (p_port->ev_mask & events);
475 /*******************************************************************************
477 ** Function port_flow_control_peer
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.
485 *******************************************************************************/
486 void port_flow_control_peer(tPORT *p_port, BOOLEAN enable, UINT16 count)
488 if (!p_port->rfc.p_mcb) {
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 */
496 /* update rx credits */
497 if (count > p_port->credit_rx) {
498 p_port->credit_rx = 0;
500 p_port->credit_rx -= count;
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));
512 p_port->credit_rx = p_port->credit_rx_max;
514 p_port->rx.peer_fc = FALSE;
517 /* else want to disable flow from peer */
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;
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;
529 /* else using TS 07.10 flow control */
531 /* if want to enable flow from peer */
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;
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);
546 /* else want to disable flow from peer */
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);
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.");
560 p_port->rx.peer_fc = TRUE;
561 RFCOMM_FlowReq (p_port->rfc.p_mcb, p_port->dlci, FALSE);