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 "osi/include/mutex.h"
27
28 #include "bt_common.h"
29 #include "bt_target.h"
30 #include "btm_int.h"
31 #include "btu.h"
32 #include "l2cdefs.h"
33 #include "port_api.h"
34 #include "port_int.h"
35 #include "rfc_int.h"
36 #include "rfcdefs.h"
37
38 static const tPORT_STATE default_port_pars = {
39 PORT_BAUD_RATE_9600,
40 PORT_8_BITS,
41 PORT_ONESTOPBIT,
42 PORT_PARITY_NO,
43 PORT_ODD_PARITY,
44 PORT_FC_OFF,
45 0, /* No rx_char */
46 PORT_XON_DC1,
47 PORT_XOFF_DC3,
48 };
49
50 /*******************************************************************************
51 *
52 * Function port_allocate_port
53 *
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
57 * clients.
58 *
59 * Returns Pointer to the PORT or NULL if not found
60 *
61 ******************************************************************************/
port_allocate_port(uint8_t dlci,BD_ADDR bd_addr)62 tPORT* port_allocate_port(uint8_t dlci, BD_ADDR bd_addr) {
63 tPORT* p_port = &rfc_cb.port.port[0];
64 uint8_t 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) yy = 0;
68
69 p_port = &rfc_cb.port.port[yy];
70 if (!p_port->in_use) {
71 memset(p_port, 0, sizeof(tPORT));
72
73 p_port->in_use = true;
74 p_port->inx = yy + 1;
75
76 /* During the open set default state for the port connection */
77 port_set_defaults(p_port);
78
79 p_port->rfc.port_timer = alarm_new("rfcomm_port.port_timer");
80 rfc_cb.rfc.last_port = yy;
81
82 p_port->dlci = dlci;
83 memcpy(p_port->bd_addr, bd_addr, BD_ADDR_LEN);
84
85 RFCOMM_TRACE_DEBUG("rfc_cb.port.port[%d]:%p allocated, last_port:%d", yy,
86 p_port, rfc_cb.rfc.last_port);
87 RFCOMM_TRACE_DEBUG(
88 "port_allocate_port:bd_addr:%02x:%02x:%02x:%02x:%02x:%02x",
89 bd_addr[0], bd_addr[1], bd_addr[2], bd_addr[3], bd_addr[4],
90 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 * Function port_set_defaults
102 *
103 * Description Set defualt port parameters
104 *
105 *
106 ******************************************************************************/
port_set_defaults(tPORT * p_port)107 void port_set_defaults(tPORT* p_port) {
108 p_port->ev_mask = 0;
109 p_port->p_callback = NULL;
110 p_port->port_ctrl = 0;
111 p_port->error = 0;
112 p_port->line_status = 0;
113 p_port->rx_flag_ev_pending = false;
114 p_port->peer_mtu = RFCOMM_DEFAULT_MTU;
115
116 p_port->user_port_pars = default_port_pars;
117 p_port->peer_port_pars = default_port_pars;
118
119 p_port->credit_tx = 0;
120 p_port->credit_rx = 0;
121
122 memset(&p_port->local_ctrl, 0, sizeof(p_port->local_ctrl));
123 memset(&p_port->peer_ctrl, 0, sizeof(p_port->peer_ctrl));
124 memset(&p_port->rx, 0, sizeof(p_port->rx));
125 memset(&p_port->tx, 0, sizeof(p_port->tx));
126
127 p_port->tx.queue = fixed_queue_new(SIZE_MAX);
128 p_port->rx.queue = fixed_queue_new(SIZE_MAX);
129 }
130
131 /*******************************************************************************
132 *
133 * Function port_select_mtu
134 *
135 * Description Select MTU which will best serve connection from our
136 * point of view.
137 * If our device is 1.2 or lower we calculate how many DH5s
138 * fit into 1 RFCOMM buffer.
139 *
140 *
141 ******************************************************************************/
port_select_mtu(tPORT * p_port)142 void port_select_mtu(tPORT* p_port) {
143 uint16_t packet_size;
144
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;
153 } else {
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
156 bytes.
157 At first calculate how many whole packets it is. MAX L2CAP is 1691 + 4
158 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
161 header overhead 1685
162
163 For EDR 2.0 packet size is 1027. So we better send RFCOMM packet as 1
164 3DH5 packet
165 1 * 1027 = 1027. Minus 4 bytes L2CAP header 1023. Minus RFCOMM 6 bytes
166 header overhead 1017 */
167 if ((L2CAP_MTU_SIZE + L2CAP_PKT_OVERHEAD) >= packet_size) {
168 p_port->mtu = ((L2CAP_MTU_SIZE + L2CAP_PKT_OVERHEAD) / packet_size *
169 packet_size) -
170 RFCOMM_DATA_OVERHEAD - L2CAP_PKT_OVERHEAD;
171 RFCOMM_TRACE_DEBUG(
172 "port_select_mtu selected %d based on connection speed",
173 p_port->mtu);
174 } else {
175 p_port->mtu = L2CAP_MTU_SIZE - RFCOMM_DATA_OVERHEAD;
176 RFCOMM_TRACE_DEBUG(
177 "port_select_mtu selected %d based on l2cap PDU size", p_port->mtu);
178 }
179 }
180 } else {
181 RFCOMM_TRACE_DEBUG("port_select_mtu application selected %d", p_port->mtu);
182 }
183 p_port->credit_rx_max = (PORT_RX_HIGH_WM / p_port->mtu);
184 if (p_port->credit_rx_max > PORT_RX_BUF_HIGH_WM)
185 p_port->credit_rx_max = PORT_RX_BUF_HIGH_WM;
186 p_port->credit_rx_low = (PORT_RX_LOW_WM / p_port->mtu);
187 if (p_port->credit_rx_low > PORT_RX_BUF_LOW_WM)
188 p_port->credit_rx_low = PORT_RX_BUF_LOW_WM;
189 p_port->rx_buf_critical = (PORT_RX_CRITICAL_WM / p_port->mtu);
190 if (p_port->rx_buf_critical > PORT_RX_BUF_CRITICAL_WM)
191 p_port->rx_buf_critical = PORT_RX_BUF_CRITICAL_WM;
192 RFCOMM_TRACE_DEBUG(
193 "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 * Function port_release_port
200 *
201 * Description Release port control block.
202 *
203 * Returns Pointer to the PORT or NULL if not found
204 *
205 ******************************************************************************/
port_release_port(tPORT * p_port)206 void port_release_port(tPORT* p_port) {
207 RFCOMM_TRACE_DEBUG("%s p_port: %p state: %d keep_handle: %d", __func__,
208 p_port, p_port->rfc.state, p_port->keep_port_handle);
209
210 mutex_global_lock();
211 BT_HDR* p_buf;
212 while ((p_buf = (BT_HDR*)fixed_queue_try_dequeue(p_port->rx.queue)) != NULL)
213 osi_free(p_buf);
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 p_port->tx.queue_size = 0;
219 mutex_global_unlock();
220
221 alarm_cancel(p_port->rfc.port_timer);
222
223 p_port->state = PORT_STATE_CLOSED;
224
225 if (p_port->rfc.state == RFC_STATE_CLOSED) {
226 if (p_port->rfc.p_mcb) {
227 p_port->rfc.p_mcb->port_inx[p_port->dlci] = 0;
228
229 /* If there are no more ports opened on this MCB release it */
230 rfc_check_mcb_active(p_port->rfc.p_mcb);
231 }
232
233 rfc_port_timer_stop(p_port);
234 fixed_queue_free(p_port->tx.queue, NULL);
235 p_port->tx.queue = NULL;
236 fixed_queue_free(p_port->rx.queue, NULL);
237 p_port->rx.queue = NULL;
238
239 if (p_port->keep_port_handle) {
240 RFCOMM_TRACE_DEBUG("%s Re-initialize handle: %d", __func__, p_port->inx);
241
242 /* save event mask and callback */
243 uint32_t mask = p_port->ev_mask;
244 tPORT_CALLBACK* p_port_cb = p_port->p_callback;
245 tPORT_STATE user_port_pars = p_port->user_port_pars;
246
247 port_set_defaults(p_port);
248
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) p_port->dlci &= 0xfe;
258
259 p_port->local_ctrl.modem_signal = p_port->default_signal_state;
260 memcpy(p_port->bd_addr, BT_BD_ANY, BD_ADDR_LEN);
261 } else {
262 RFCOMM_TRACE_DEBUG("%s Clean-up handle: %d", __func__, p_port->inx);
263 alarm_free(p_port->rfc.port_timer);
264 memset(p_port, 0, sizeof(tPORT));
265 }
266 }
267 }
268
269 /*******************************************************************************
270 *
271 * Function port_find_mcb
272 *
273 * Description This function checks if connection exists to device with
274 * the BD_ADDR.
275 *
276 ******************************************************************************/
port_find_mcb(BD_ADDR bd_addr)277 tRFC_MCB* port_find_mcb(BD_ADDR bd_addr) {
278 int i;
279
280 for (i = 0; i < MAX_BD_CONNECTIONS; i++) {
281 if ((rfc_cb.port.rfc_mcb[i].state != RFC_MX_STATE_IDLE) &&
282 !memcmp(rfc_cb.port.rfc_mcb[i].bd_addr, bd_addr, BD_ADDR_LEN)) {
283 /* Multiplexer channel found do not change anything */
284 RFCOMM_TRACE_DEBUG(
285 "port_find_mcb: found bd_addr:%02x:%02x:%02x:%02x:%02x:%02x",
286 bd_addr[0], bd_addr[1], bd_addr[2], bd_addr[3], bd_addr[4],
287 bd_addr[5]);
288 RFCOMM_TRACE_DEBUG(
289 "port_find_mcb: rfc_cb.port.rfc_mcb:index:%d, %p, lcid:%d", i,
290 &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(
295 "port_find_mcb: not found, bd_addr:%02x:%02x:%02x:%02x:%02x:%02x",
296 bd_addr[0], bd_addr[1], bd_addr[2], bd_addr[3], bd_addr[4], bd_addr[5]);
297 return (NULL);
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 ******************************************************************************/
port_find_mcb_dlci_port(tRFC_MCB * p_mcb,uint8_t dlci)312 tPORT* port_find_mcb_dlci_port(tRFC_MCB* p_mcb, uint8_t dlci) {
313 uint8_t inx;
314
315 if (!p_mcb) return (NULL);
316
317 if (dlci > RFCOMM_MAX_DLCI) return (NULL);
318
319 inx = p_mcb->port_inx[dlci];
320 if (inx == 0) {
321 RFCOMM_TRACE_DEBUG(
322 "port_find_mcb_dlci_port: p_mcb:%p, port_inx[dlci:%d] is 0", p_mcb,
323 dlci);
324 return (NULL);
325 } else
326 return (&rfc_cb.port.port[inx - 1]);
327 }
328
329 /*******************************************************************************
330 *
331 * Function port_find_dlci_port
332 *
333 * Description Find port with DLCI not assigned to multiplexer channel
334 *
335 * Returns Pointer to the PORT or NULL if not found
336 *
337 ******************************************************************************/
port_find_dlci_port(uint8_t dlci)338 tPORT* port_find_dlci_port(uint8_t dlci) {
339 uint16_t i;
340 tPORT* p_port;
341
342 for (i = 0; i < MAX_RFC_PORTS; i++) {
343 p_port = &rfc_cb.port.port[i];
344
345 if (p_port->in_use && (p_port->rfc.p_mcb == NULL)) {
346 if (p_port->dlci == dlci) {
347 return (p_port);
348 } else if ((dlci & 0x01) && (p_port->dlci == (dlci - 1))) {
349 p_port->dlci++;
350 return (p_port);
351 }
352 }
353 }
354 return (NULL);
355 }
356
357 /*******************************************************************************
358 *
359 * Function port_find_port
360 *
361 * Description Find port with DLCI, BD_ADDR
362 *
363 * Returns Pointer to the PORT or NULL if not found
364 *
365 ******************************************************************************/
port_find_port(uint8_t dlci,BD_ADDR bd_addr)366 tPORT* port_find_port(uint8_t dlci, BD_ADDR bd_addr) {
367 uint16_t i;
368 tPORT* p_port;
369
370 for (i = 0; i < MAX_RFC_PORTS; i++) {
371 p_port = &rfc_cb.port.port[i];
372 if (p_port->in_use && (p_port->dlci == dlci) &&
373 !memcmp(p_port->bd_addr, bd_addr, BD_ADDR_LEN)) {
374 return (p_port);
375 }
376 }
377 return (NULL);
378 }
379
380 /*******************************************************************************
381 *
382 * Function port_flow_control_user
383 *
384 * Description Check the current user flow control and if necessary return
385 * events to be send to the user based on the user's specified
386 * flow control type.
387 *
388 * Returns event mask to be returned to the application
389 *
390 ******************************************************************************/
port_flow_control_user(tPORT * p_port)391 uint32_t port_flow_control_user(tPORT* p_port) {
392 uint32_t event = 0;
393
394 /* Flow control to the user can be caused by flow controlling by the peer */
395 /* (FlowInd, or flow control by the peer RFCOMM (Fcon) or internally if */
396 /* tx_queue is full */
397 bool fc = p_port->tx.peer_fc || !p_port->rfc.p_mcb ||
398 !p_port->rfc.p_mcb->peer_ready ||
399 (p_port->tx.queue_size > PORT_TX_HIGH_WM) ||
400 (fixed_queue_length(p_port->tx.queue) > PORT_TX_BUF_HIGH_WM);
401
402 if (p_port->tx.user_fc == fc) return (0);
403
404 p_port->tx.user_fc = fc;
405
406 if (fc)
407 event = PORT_EV_FC;
408 else
409 event = PORT_EV_FC | PORT_EV_FCS;
410
411 return (event);
412 }
413
414 /*******************************************************************************
415 *
416 * Function port_get_signal_changes
417 *
418 * Description Check modem signals that has been changed
419 *
420 * Returns event mask to be returned to the application
421 *
422 ******************************************************************************/
port_get_signal_changes(tPORT * p_port,uint8_t old_signals,uint8_t signal)423 uint32_t port_get_signal_changes(tPORT* p_port, uint8_t old_signals,
424 uint8_t signal) {
425 uint8_t changed_signals = (signal ^ old_signals);
426 uint32_t events = 0;
427
428 if (changed_signals & PORT_DTRDSR_ON) {
429 events |= PORT_EV_DSR;
430
431 if (signal & PORT_DTRDSR_ON) events |= PORT_EV_DSRS;
432 }
433
434 if (changed_signals & PORT_CTSRTS_ON) {
435 events |= PORT_EV_CTS;
436
437 if (signal & PORT_CTSRTS_ON) events |= PORT_EV_CTSS;
438 }
439
440 if (changed_signals & PORT_RING_ON) events |= PORT_EV_RING;
441
442 if (changed_signals & PORT_DCD_ON) {
443 events |= PORT_EV_RLSD;
444
445 if (signal & PORT_DCD_ON) events |= PORT_EV_RLSDS;
446 }
447
448 return (p_port->ev_mask & events);
449 }
450
451 /*******************************************************************************
452 *
453 * Function port_flow_control_peer
454 *
455 * Description Send flow control messages to the peer for both enabling
456 * and disabling flow control, for both credit-based and
457 * TS 07.10 flow control mechanisms.
458 *
459 * Returns nothing
460 *
461 ******************************************************************************/
port_flow_control_peer(tPORT * p_port,bool enable,uint16_t count)462 void port_flow_control_peer(tPORT* p_port, bool enable, uint16_t count) {
463 if (!p_port->rfc.p_mcb) return;
464
465 /* If using credit based flow control */
466 if (p_port->rfc.p_mcb->flow == PORT_FC_CREDIT) {
467 /* if want to enable flow from peer */
468 if (enable) {
469 /* update rx credits */
470 if (count > p_port->credit_rx) {
471 p_port->credit_rx = 0;
472 } else {
473 p_port->credit_rx -= count;
474 }
475
476 /* If credit count is less than low credit watermark, and user */
477 /* did not force flow control, send a credit update */
478 /* There might be a special case when we just adjusted rx_max */
479 if ((p_port->credit_rx <= p_port->credit_rx_low) && !p_port->rx.user_fc &&
480 (p_port->credit_rx_max > p_port->credit_rx)) {
481 rfc_send_credit(p_port->rfc.p_mcb, p_port->dlci,
482 (uint8_t)(p_port->credit_rx_max - p_port->credit_rx));
483
484 p_port->credit_rx = p_port->credit_rx_max;
485
486 p_port->rx.peer_fc = false;
487 }
488 }
489 /* else want to disable flow from peer */
490 else {
491 /* if client registered data callback, just do what they want */
492 if (p_port->p_data_callback || p_port->p_data_co_callback) {
493 p_port->rx.peer_fc = true;
494 }
495 /* if queue count reached credit rx max, set peer fc */
496 else if (fixed_queue_length(p_port->rx.queue) >= p_port->credit_rx_max) {
497 p_port->rx.peer_fc = true;
498 }
499 }
500 }
501 /* else using TS 07.10 flow control */
502 else {
503 /* if want to enable flow from peer */
504 if (enable) {
505 /* If rfcomm suspended traffic from the peer based on the rx_queue_size */
506 /* check if it can be resumed now */
507 if (p_port->rx.peer_fc && (p_port->rx.queue_size < PORT_RX_LOW_WM) &&
508 (fixed_queue_length(p_port->rx.queue) < PORT_RX_BUF_LOW_WM)) {
509 p_port->rx.peer_fc = false;
510
511 /* If user did not force flow control allow traffic now */
512 if (!p_port->rx.user_fc)
513 RFCOMM_FlowReq(p_port->rfc.p_mcb, p_port->dlci, true);
514 }
515 }
516 /* else want to disable flow from peer */
517 else {
518 /* if client registered data callback, just do what they want */
519 if (p_port->p_data_callback || p_port->p_data_co_callback) {
520 p_port->rx.peer_fc = true;
521 RFCOMM_FlowReq(p_port->rfc.p_mcb, p_port->dlci, false);
522 }
523 /* Check the size of the rx queue. If it exceeds certain */
524 /* level and flow control has not been sent to the peer do it now */
525 else if (((p_port->rx.queue_size > PORT_RX_HIGH_WM) ||
526 (fixed_queue_length(p_port->rx.queue) > PORT_RX_BUF_HIGH_WM)) &&
527 !p_port->rx.peer_fc) {
528 RFCOMM_TRACE_EVENT("PORT_DataInd Data reached HW. Sending FC set.");
529
530 p_port->rx.peer_fc = true;
531 RFCOMM_FlowReq(p_port->rfc.p_mcb, p_port->dlci, false);
532 }
533 }
534 }
535 }
536