summaryrefslogtreecommitdiffstats
path: root/stack/rfcomm/port_api.c
diff options
context:
space:
mode:
authorzzy <zhenye@broadcom.com>2013-08-09 17:52:52 -0700
committerMatthew Xie <mattx@google.com>2013-08-13 16:50:34 -0700
commit181adbef76c194e257639daecb486bfc9a0ad037 (patch)
tree5b52cda4d6a28ea1f05916266955f6ea120e6a4e /stack/rfcomm/port_api.c
parent153767ee55e16c45235e590305bdbc0ba952da63 (diff)
downloadandroid_system_bt-181adbef76c194e257639daecb486bfc9a0ad037.tar.gz
android_system_bt-181adbef76c194e257639daecb486bfc9a0ad037.tar.bz2
android_system_bt-181adbef76c194e257639daecb486bfc9a0ad037.zip
Fixed issue that failed to update rfc credit to peer when host can not handle the incoming packets fast enough
Bug 10233699: Bluetooth sockets block indefinitely on read(...)
Diffstat (limited to 'stack/rfcomm/port_api.c')
-rw-r--r--stack/rfcomm/port_api.c79
1 files changed, 79 insertions, 0 deletions
diff --git a/stack/rfcomm/port_api.c b/stack/rfcomm/port_api.c
index cba153e23..9ea1fcabe 100644
--- a/stack/rfcomm/port_api.c
+++ b/stack/rfcomm/port_api.c
@@ -845,6 +845,85 @@ int PORT_FlowControl (UINT16 handle, BOOLEAN enable)
}
return (PORT_SUCCESS);
}
+/*******************************************************************************
+**
+** Function PORT_FlowControl_MaxCredit
+**
+** Description This function directs a specified connection to pass
+** flow control message to the peer device. Enable flag passed
+** shows if port can accept more data. It also sends max credit
+** when data flow enabled
+**
+** Parameters: handle - Handle returned in the RFCOMM_CreateConnection
+** enable - enables data flow
+**
+*******************************************************************************/
+
+int PORT_FlowControl_MaxCredit (UINT16 handle, BOOLEAN enable)
+{
+ tPORT *p_port;
+ BOOLEAN old_fc;
+ UINT32 events;
+
+ RFCOMM_TRACE_API2 ("PORT_FlowControl() handle:%d enable: %d", handle, enable);
+
+ /* Check if handle is valid to avoid crashing */
+ if ((handle == 0) || (handle > MAX_RFC_PORTS))
+ {
+ return (PORT_BAD_HANDLE);
+ }
+
+ p_port = &rfc_cb.port.port[handle - 1];
+
+ if (!p_port->in_use || (p_port->state == PORT_STATE_CLOSED))
+ {
+ return (PORT_NOT_OPENED);
+ }
+
+ if (!p_port->rfc.p_mcb)
+ {
+ return (PORT_NOT_OPENED);
+ }
+
+ p_port->rx.user_fc = !enable;
+
+ if (p_port->rfc.p_mcb->flow == PORT_FC_CREDIT)
+ {
+ if (!p_port->rx.user_fc)
+ {
+ port_flow_control_peer(p_port, TRUE, p_port->credit_rx);
+ }
+ }
+ else
+ {
+ old_fc = p_port->local_ctrl.fc;
+
+ /* FC is set if user is set or peer is set */
+ p_port->local_ctrl.fc = (p_port->rx.user_fc | p_port->rx.peer_fc);
+
+ if (p_port->local_ctrl.fc != old_fc)
+ port_start_control (p_port);
+ }
+
+ /* Need to take care of the case when we could not deliver events */
+ /* to the application because we were flow controlled */
+ if (enable && (p_port->rx.queue_size != 0))
+ {
+ events = PORT_EV_RXCHAR;
+ if (p_port->rx_flag_ev_pending)
+ {
+ p_port->rx_flag_ev_pending = FALSE;
+ events |= PORT_EV_RXFLAG;
+ }
+
+ events &= p_port->ev_mask;
+ if (p_port->p_callback && events)
+ {
+ p_port->p_callback (events, p_port->inx);
+ }
+ }
+ return (PORT_SUCCESS);
+}
/*******************************************************************************