aboutsummaryrefslogtreecommitdiff
path: root/net
diff options
context:
space:
mode:
Diffstat (limited to 'net')
-rw-r--r--net/bluetooth/l2cap_core.c25
-rw-r--r--net/bluetooth/l2cap_sock.c13
2 files changed, 36 insertions, 2 deletions
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index c90f6ffae..2bb685312 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -1874,13 +1874,21 @@ done:
int __l2cap_wait_ack(struct sock *sk)
{
struct l2cap_chan *chan = l2cap_pi(sk)->chan;
+ struct l2cap_conn *conn;
DECLARE_WAITQUEUE(wait, current);
int err = 0;
int timeo = HZ/5;
add_wait_queue(sk_sleep(sk), &wait);
set_current_state(TASK_INTERRUPTIBLE);
- while (chan->unacked_frames > 0 && chan->conn) {
+
+ conn = chan->conn;
+ if (conn)
+ mutex_lock(&conn->chan_lock);
+ l2cap_chan_lock(chan);
+ lock_sock(sk);
+
+ while (chan->unacked_frames > 0 && conn) {
if (!timeo)
timeo = HZ/5;
@@ -1890,14 +1898,29 @@ int __l2cap_wait_ack(struct sock *sk)
}
release_sock(sk);
+ l2cap_chan_unlock(chan);
+ if (conn)
+ mutex_unlock(&conn->chan_lock);
+
timeo = schedule_timeout(timeo);
+
+ if (conn)
+ mutex_lock(&conn->chan_lock);
+ l2cap_chan_lock(chan);
lock_sock(sk);
+
set_current_state(TASK_INTERRUPTIBLE);
err = sock_error(sk);
if (err)
break;
}
+
+ release_sock(sk);
+ l2cap_chan_unlock(chan);
+ if (conn)
+ mutex_unlock(&conn->chan_lock);
+
set_current_state(TASK_RUNNING);
remove_wait_queue(sk_sleep(sk), &wait);
return err;
diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c
index eaab0f580..9d7b2ee5e 100644
--- a/net/bluetooth/l2cap_sock.c
+++ b/net/bluetooth/l2cap_sock.c
@@ -882,9 +882,20 @@ static int l2cap_sock_shutdown(struct socket *sock, int how)
lock_sock(sk);
if (!sk->sk_shutdown) {
- if (chan->mode == L2CAP_MODE_ERTM)
+ if (chan->mode == L2CAP_MODE_ERTM) {
+ release_sock(sk);
+ l2cap_chan_unlock(chan);
+ if (conn)
+ mutex_unlock(&conn->chan_lock);
+
err = __l2cap_wait_ack(sk);
+ if (conn)
+ mutex_lock(&conn->chan_lock);
+ l2cap_chan_lock(chan);
+ lock_sock(sk);
+ }
+
sk->sk_shutdown = SHUTDOWN_MASK;
release_sock(sk);