diff options
author | Gustavo F. Padovan <padovan@profusion.mobi> | 2010-05-01 16:15:44 -0300 |
---|---|---|
committer | Marcel Holtmann <marcel@holtmann.org> | 2010-05-10 09:28:53 +0200 |
commit | 6161c0382bbab883a634d284f7367a88bbe88534 (patch) | |
tree | 86b4de3160054b0507d37a47351260e48073f579 | |
parent | 1890d36bb556a27684ad29654a9898ab9a5f57ee (diff) | |
download | linux-6161c0382bbab883a634d284f7367a88bbe88534.tar.bz2 |
Bluetooth: Add wait_queue to wait ack of all sent packets
To guarantee that all packets we sent were received we need to wait for
theirs ack before shutdown the socket.
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>
-rw-r--r-- | net/bluetooth/l2cap.c | 34 |
1 files changed, 34 insertions, 0 deletions
diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 103e4b54a86a..9d514f9dbc0f 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -1242,6 +1242,37 @@ static int l2cap_sock_getname(struct socket *sock, struct sockaddr *addr, int *l return 0; } +static int __l2cap_wait_ack(struct sock *sk) +{ + DECLARE_WAITQUEUE(wait, current); + int err = 0; + int timeo = HZ/5; + + add_wait_queue(sk->sk_sleep, &wait); + while ((l2cap_pi(sk)->unacked_frames > 0 && l2cap_pi(sk)->conn)) { + set_current_state(TASK_INTERRUPTIBLE); + + if (!timeo) + timeo = HZ/5; + + if (signal_pending(current)) { + err = sock_intr_errno(timeo); + break; + } + + release_sock(sk); + timeo = schedule_timeout(timeo); + lock_sock(sk); + + err = sock_error(sk); + if (err) + break; + } + set_current_state(TASK_RUNNING); + remove_wait_queue(sk->sk_sleep, &wait); + return err; +} + static void l2cap_monitor_timeout(unsigned long arg) { struct sock *sk = (void *) arg; @@ -2059,6 +2090,9 @@ static int l2cap_sock_shutdown(struct socket *sock, int how) lock_sock(sk); if (!sk->sk_shutdown) { + if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM) + err = __l2cap_wait_ack(sk); + sk->sk_shutdown = SHUTDOWN_MASK; l2cap_sock_clear_timer(sk); __l2cap_sock_close(sk, 0); |