diff options
author | Gustavo F. Padovan <padovan@profusion.mobi> | 2010-06-21 18:39:50 -0400 |
---|---|---|
committer | Marcel Holtmann <marcel@holtmann.org> | 2010-07-21 13:39:09 -0400 |
commit | 712132eb541e4a76afad97898dc0ce6b6c0032d8 (patch) | |
tree | 5e4b44c035a02c55563265f1e8036bfb67ece9d4 /net | |
parent | 218bb9dfd21472128f86b38ad2eab123205c2991 (diff) |
Bluetooth: Improve ERTM local busy handling
Now we also check if can push skb userspace just after receive a new
skb instead of only wait the l2cap_busy_work wake up from time to time
to check the local busy condition.
Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
Diffstat (limited to 'net')
-rw-r--r-- | net/bluetooth/l2cap.c | 83 |
1 files changed, 47 insertions, 36 deletions
diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index cf4481f7f566..6b839d682143 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c | |||
@@ -3606,6 +3606,46 @@ disconnect: | |||
3606 | return 0; | 3606 | return 0; |
3607 | } | 3607 | } |
3608 | 3608 | ||
3609 | static int l2cap_try_push_rx_skb(struct sock *sk) | ||
3610 | { | ||
3611 | struct l2cap_pinfo *pi = l2cap_pi(sk); | ||
3612 | struct sk_buff *skb; | ||
3613 | u16 control; | ||
3614 | int err; | ||
3615 | |||
3616 | while ((skb = skb_dequeue(BUSY_QUEUE(sk)))) { | ||
3617 | control = bt_cb(skb)->sar << L2CAP_CTRL_SAR_SHIFT; | ||
3618 | err = l2cap_ertm_reassembly_sdu(sk, skb, control); | ||
3619 | if (err < 0) { | ||
3620 | skb_queue_head(BUSY_QUEUE(sk), skb); | ||
3621 | return -EBUSY; | ||
3622 | } | ||
3623 | |||
3624 | pi->buffer_seq = (pi->buffer_seq + 1) % 64; | ||
3625 | } | ||
3626 | |||
3627 | if (!(pi->conn_state & L2CAP_CONN_RNR_SENT)) | ||
3628 | goto done; | ||
3629 | |||
3630 | control = pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT; | ||
3631 | control |= L2CAP_SUPER_RCV_READY | L2CAP_CTRL_POLL; | ||
3632 | l2cap_send_sframe(pi, control); | ||
3633 | l2cap_pi(sk)->retry_count = 1; | ||
3634 | |||
3635 | del_timer(&pi->retrans_timer); | ||
3636 | __mod_monitor_timer(); | ||
3637 | |||
3638 | l2cap_pi(sk)->conn_state |= L2CAP_CONN_WAIT_F; | ||
3639 | |||
3640 | done: | ||
3641 | pi->conn_state &= ~L2CAP_CONN_LOCAL_BUSY; | ||
3642 | pi->conn_state &= ~L2CAP_CONN_RNR_SENT; | ||
3643 | |||
3644 | BT_DBG("sk %p, Exit local busy", sk); | ||
3645 | |||
3646 | return 0; | ||
3647 | } | ||
3648 | |||
3609 | static void l2cap_busy_work(struct work_struct *work) | 3649 | static void l2cap_busy_work(struct work_struct *work) |
3610 | { | 3650 | { |
3611 | DECLARE_WAITQUEUE(wait, current); | 3651 | DECLARE_WAITQUEUE(wait, current); |
@@ -3614,7 +3654,6 @@ static void l2cap_busy_work(struct work_struct *work) | |||
3614 | struct sock *sk = (struct sock *)pi; | 3654 | struct sock *sk = (struct sock *)pi; |
3615 | int n_tries = 0, timeo = HZ/5, err; | 3655 | int n_tries = 0, timeo = HZ/5, err; |
3616 | struct sk_buff *skb; | 3656 | struct sk_buff *skb; |
3617 | u16 control; | ||
3618 | 3657 | ||
3619 | lock_sock(sk); | 3658 | lock_sock(sk); |
3620 | 3659 | ||
@@ -3625,7 +3664,7 @@ static void l2cap_busy_work(struct work_struct *work) | |||
3625 | if (n_tries++ > L2CAP_LOCAL_BUSY_TRIES) { | 3664 | if (n_tries++ > L2CAP_LOCAL_BUSY_TRIES) { |
3626 | err = -EBUSY; | 3665 | err = -EBUSY; |
3627 | l2cap_send_disconn_req(pi->conn, sk, EBUSY); | 3666 | l2cap_send_disconn_req(pi->conn, sk, EBUSY); |
3628 | goto done; | 3667 | break; |
3629 | } | 3668 | } |
3630 | 3669 | ||
3631 | if (!timeo) | 3670 | if (!timeo) |
@@ -3633,7 +3672,7 @@ static void l2cap_busy_work(struct work_struct *work) | |||
3633 | 3672 | ||
3634 | if (signal_pending(current)) { | 3673 | if (signal_pending(current)) { |
3635 | err = sock_intr_errno(timeo); | 3674 | err = sock_intr_errno(timeo); |
3636 | goto done; | 3675 | break; |
3637 | } | 3676 | } |
3638 | 3677 | ||
3639 | release_sock(sk); | 3678 | release_sock(sk); |
@@ -3642,42 +3681,12 @@ static void l2cap_busy_work(struct work_struct *work) | |||
3642 | 3681 | ||
3643 | err = sock_error(sk); | 3682 | err = sock_error(sk); |
3644 | if (err) | 3683 | if (err) |
3645 | goto done; | 3684 | break; |
3646 | |||
3647 | while ((skb = skb_dequeue(BUSY_QUEUE(sk)))) { | ||
3648 | control = bt_cb(skb)->sar << L2CAP_CTRL_SAR_SHIFT; | ||
3649 | err = l2cap_ertm_reassembly_sdu(sk, skb, control); | ||
3650 | if (err < 0) { | ||
3651 | skb_queue_head(BUSY_QUEUE(sk), skb); | ||
3652 | break; | ||
3653 | } | ||
3654 | |||
3655 | pi->buffer_seq = (pi->buffer_seq + 1) % 64; | ||
3656 | } | ||
3657 | 3685 | ||
3658 | if (!skb) | 3686 | if (l2cap_try_push_rx_skb(sk) == 0) |
3659 | break; | 3687 | break; |
3660 | } | 3688 | } |
3661 | 3689 | ||
3662 | if (!(pi->conn_state & L2CAP_CONN_RNR_SENT)) | ||
3663 | goto done; | ||
3664 | |||
3665 | control = pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT; | ||
3666 | control |= L2CAP_SUPER_RCV_READY | L2CAP_CTRL_POLL; | ||
3667 | l2cap_send_sframe(pi, control); | ||
3668 | l2cap_pi(sk)->retry_count = 1; | ||
3669 | |||
3670 | del_timer(&pi->retrans_timer); | ||
3671 | __mod_monitor_timer(); | ||
3672 | |||
3673 | l2cap_pi(sk)->conn_state |= L2CAP_CONN_WAIT_F; | ||
3674 | |||
3675 | done: | ||
3676 | pi->conn_state &= ~L2CAP_CONN_LOCAL_BUSY; | ||
3677 | pi->conn_state &= ~L2CAP_CONN_RNR_SENT; | ||
3678 | |||
3679 | BT_DBG("sk %p, Exit local busy", sk); | ||
3680 | |||
3681 | set_current_state(TASK_RUNNING); | 3690 | set_current_state(TASK_RUNNING); |
3682 | remove_wait_queue(sk_sleep(sk), &wait); | 3691 | remove_wait_queue(sk_sleep(sk), &wait); |
3683 | 3692 | ||
@@ -3692,7 +3701,9 @@ static int l2cap_push_rx_skb(struct sock *sk, struct sk_buff *skb, u16 control) | |||
3692 | if (pi->conn_state & L2CAP_CONN_LOCAL_BUSY) { | 3701 | if (pi->conn_state & L2CAP_CONN_LOCAL_BUSY) { |
3693 | bt_cb(skb)->sar = control >> L2CAP_CTRL_SAR_SHIFT; | 3702 | bt_cb(skb)->sar = control >> L2CAP_CTRL_SAR_SHIFT; |
3694 | __skb_queue_tail(BUSY_QUEUE(sk), skb); | 3703 | __skb_queue_tail(BUSY_QUEUE(sk), skb); |
3695 | return -EBUSY; | 3704 | return l2cap_try_push_rx_skb(sk); |
3705 | |||
3706 | |||
3696 | } | 3707 | } |
3697 | 3708 | ||
3698 | err = l2cap_ertm_reassembly_sdu(sk, skb, control); | 3709 | err = l2cap_ertm_reassembly_sdu(sk, skb, control); |