Bluetooth: Fix bug in l2cap_ertm_send() behavior
authorGustavo F. Padovan <padovan@profusion.mobi>
Tue, 1 Jun 2010 21:52:58 +0000 (18:52 -0300)
committerMarcel Holtmann <marcel@holtmann.org>
Wed, 21 Jul 2010 17:39:04 +0000 (10:39 -0700)
This patch makes l2cap_ertm_send() similar to the Send-Data action of
the ERTM spec. We shall not check for RemoteBusy or WAIT_F state
inside l2cap_ertm_send().

Such checks were causing a bug in the retransmission logic of ERTM and
making ERTM stalls until the ACL is dropped.

Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
Reviewed-by: João Paulo Rechi Vita <jprvita@profusion.mobi>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
net/bluetooth/l2cap.c

index 108c2f290ac52b8f6312d29402e1727c5a660ddc..69f098d98141b9a360b1d38099fda59b2ec06980 100644 (file)
@@ -1415,11 +1415,8 @@ static int l2cap_ertm_send(struct sock *sk)
        u16 control, fcs;
        int nsent = 0;
 
-       if (pi->conn_state & L2CAP_CONN_WAIT_F)
-               return 0;
 
-       while ((skb = sk->sk_send_head) && (!l2cap_tx_window_full(sk)) &&
-                       !(pi->conn_state & L2CAP_CONN_REMOTE_BUSY)) {
+       while ((skb = sk->sk_send_head) && (!l2cap_tx_window_full(sk))) {
 
                if (pi->remote_max_tx &&
                                bt_cb(skb)->retries == pi->remote_max_tx) {
@@ -1792,6 +1789,11 @@ static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct ms
                if (pi->mode == L2CAP_MODE_STREAMING) {
                        err = l2cap_streaming_send(sk);
                } else {
+                       if (pi->conn_state & L2CAP_CONN_REMOTE_BUSY &&
+                                       pi->conn_state && L2CAP_CONN_WAIT_F) {
+                               err = len;
+                               break;
+                       }
                        spin_lock_bh(&pi->send_lock);
                        err = l2cap_ertm_send(sk);
                        spin_unlock_bh(&pi->send_lock);
@@ -3378,8 +3380,6 @@ static inline void l2cap_send_i_or_rr_or_rnr(struct sock *sk)
        if (pi->conn_state & L2CAP_CONN_REMOTE_BUSY && pi->unacked_frames > 0)
                __mod_retrans_timer();
 
-       pi->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
-
        spin_lock_bh(&pi->send_lock);
        l2cap_ertm_send(sk);
        spin_unlock_bh(&pi->send_lock);