diff options
author | zzy <zhenye@broadcom.com> | 2013-08-09 17:52:52 -0700 |
---|---|---|
committer | Matthew Xie <mattx@google.com> | 2013-08-13 16:50:34 -0700 |
commit | 181adbef76c194e257639daecb486bfc9a0ad037 (patch) | |
tree | 5b52cda4d6a28ea1f05916266955f6ea120e6a4e /stack/rfcomm/port_api.c | |
parent | 153767ee55e16c45235e590305bdbc0ba952da63 (diff) | |
download | android_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.c | 79 |
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); +} /******************************************************************************* |