|
@@ -1111,6 +1111,8 @@ static int l2cap_sock_shutdown(struct socket *sock, int how)
|
|
|
if (!sk)
|
|
|
return 0;
|
|
|
|
|
|
+ lock_sock(sk);
|
|
|
+
|
|
|
if (sk->sk_shutdown)
|
|
|
goto shutdown_already;
|
|
|
|
|
@@ -1122,25 +1124,37 @@ static int l2cap_sock_shutdown(struct socket *sock, int how)
|
|
|
chan = l2cap_pi(sk)->chan;
|
|
|
/* prevent chan structure from being freed whilst unlocked */
|
|
|
l2cap_chan_hold(chan);
|
|
|
- conn = chan->conn;
|
|
|
|
|
|
BT_DBG("chan %p state %s", chan, state_to_string(chan->state));
|
|
|
|
|
|
- if (conn)
|
|
|
- mutex_lock(&conn->chan_lock);
|
|
|
-
|
|
|
- l2cap_chan_lock(chan);
|
|
|
- lock_sock(sk);
|
|
|
-
|
|
|
if (chan->mode == L2CAP_MODE_ERTM &&
|
|
|
chan->unacked_frames > 0 &&
|
|
|
chan->state == BT_CONNECTED)
|
|
|
err = __l2cap_wait_ack(sk, chan);
|
|
|
|
|
|
sk->sk_shutdown = SHUTDOWN_MASK;
|
|
|
-
|
|
|
release_sock(sk);
|
|
|
+
|
|
|
+ l2cap_chan_lock(chan);
|
|
|
+ conn = chan->conn;
|
|
|
+ if (conn)
|
|
|
+ /* prevent conn structure from being freed */
|
|
|
+ l2cap_conn_get(conn);
|
|
|
+ l2cap_chan_unlock(chan);
|
|
|
+
|
|
|
+ if (conn)
|
|
|
+ /* mutex lock must be taken before l2cap_chan_lock() */
|
|
|
+ mutex_lock(&conn->chan_lock);
|
|
|
+
|
|
|
+ l2cap_chan_lock(chan);
|
|
|
l2cap_chan_close(chan, 0);
|
|
|
+ l2cap_chan_unlock(chan);
|
|
|
+
|
|
|
+ if (conn) {
|
|
|
+ mutex_unlock(&conn->chan_lock);
|
|
|
+ l2cap_conn_put(conn);
|
|
|
+ }
|
|
|
+
|
|
|
lock_sock(sk);
|
|
|
|
|
|
if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime &&
|
|
@@ -1148,20 +1162,16 @@ static int l2cap_sock_shutdown(struct socket *sock, int how)
|
|
|
err = bt_sock_wait_state(sk, BT_CLOSED,
|
|
|
sk->sk_lingertime);
|
|
|
|
|
|
+ l2cap_chan_put(chan);
|
|
|
+ sock_put(sk);
|
|
|
+
|
|
|
+shutdown_already:
|
|
|
if (!err && sk->sk_err)
|
|
|
err = -sk->sk_err;
|
|
|
|
|
|
release_sock(sk);
|
|
|
- l2cap_chan_unlock(chan);
|
|
|
-
|
|
|
- if (conn)
|
|
|
- mutex_unlock(&conn->chan_lock);
|
|
|
|
|
|
- l2cap_chan_put(chan);
|
|
|
- sock_put(sk);
|
|
|
-
|
|
|
-shutdown_already:
|
|
|
- BT_DBG("err: %d", err);
|
|
|
+ BT_DBG("Sock shutdown complete err: %d", err);
|
|
|
|
|
|
return err;
|
|
|
}
|