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