Merge tag 'hwmon-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck...
[firefly-linux-kernel-4.4.55.git] / net / bluetooth / sco.c
index 9868ec7c7dc47f37bdc3d1da25718e39dbab9490..7ee9e4ab00f882f827f7b63361dc82a24ca72a23 100644 (file)
@@ -53,9 +53,6 @@ struct sco_conn {
 #define sco_conn_lock(c)       spin_lock(&c->lock);
 #define sco_conn_unlock(c)     spin_unlock(&c->lock);
 
-static void __sco_chan_add(struct sco_conn *conn, struct sock *sk, struct sock *parent);
-static void sco_chan_del(struct sock *sk, int err);
-
 static void sco_sock_close(struct sock *sk);
 static void sco_sock_kill(struct sock *sk);
 
@@ -72,6 +69,9 @@ struct sco_pinfo {
 };
 
 /* ---- SCO timers ---- */
+#define SCO_CONN_TIMEOUT       (HZ * 40)
+#define SCO_DISCONN_TIMEOUT    (HZ * 2)
+
 static void sco_sock_timeout(unsigned long arg)
 {
        struct sock *sk = (struct sock *) arg;
@@ -127,13 +127,31 @@ static struct sco_conn *sco_conn_add(struct hci_conn *hcon)
        return conn;
 }
 
-static struct sock *sco_chan_get(struct sco_conn *conn)
+/* Delete channel.
+ * Must be called on the locked socket. */
+static void sco_chan_del(struct sock *sk, int err)
 {
-       struct sock *sk = NULL;
-       sco_conn_lock(conn);
-       sk = conn->sk;
-       sco_conn_unlock(conn);
-       return sk;
+       struct sco_conn *conn;
+
+       conn = sco_pi(sk)->conn;
+
+       BT_DBG("sk %p, conn %p, err %d", sk, conn, err);
+
+       if (conn) {
+               sco_conn_lock(conn);
+               conn->sk = NULL;
+               sco_pi(sk)->conn = NULL;
+               sco_conn_unlock(conn);
+
+               if (conn->hcon)
+                       hci_conn_drop(conn->hcon);
+       }
+
+       sk->sk_state = BT_CLOSED;
+       sk->sk_err   = err;
+       sk->sk_state_change(sk);
+
+       sock_set_flag(sk, SOCK_ZAPPED);
 }
 
 static int sco_conn_del(struct hci_conn *hcon, int err)
@@ -147,7 +165,10 @@ static int sco_conn_del(struct hci_conn *hcon, int err)
        BT_DBG("hcon %p conn %p, err %d", hcon, conn, err);
 
        /* Kill socket */
-       sk = sco_chan_get(conn);
+       sco_conn_lock(conn);
+       sk = conn->sk;
+       sco_conn_unlock(conn);
+
        if (sk) {
                bh_lock_sock(sk);
                sco_sock_clear_timer(sk);
@@ -161,6 +182,17 @@ static int sco_conn_del(struct hci_conn *hcon, int err)
        return 0;
 }
 
+static void __sco_chan_add(struct sco_conn *conn, struct sock *sk, struct sock *parent)
+{
+       BT_DBG("conn %p", conn);
+
+       sco_pi(sk)->conn = conn;
+       conn->sk = sk;
+
+       if (parent)
+               bt_accept_enqueue(parent, sk);
+}
+
 static int sco_chan_add(struct sco_conn *conn, struct sock *sk,
                        struct sock *parent)
 {
@@ -265,7 +297,11 @@ static int sco_send_frame(struct sock *sk, struct msghdr *msg, int len)
 
 static void sco_recv_frame(struct sco_conn *conn, struct sk_buff *skb)
 {
-       struct sock *sk = sco_chan_get(conn);
+       struct sock *sk;
+
+       sco_conn_lock(conn);
+       sk = conn->sk;
+       sco_conn_unlock(conn);
 
        if (!sk)
                goto drop;
@@ -934,7 +970,8 @@ static int sco_sock_shutdown(struct socket *sock, int how)
                sco_sock_clear_timer(sk);
                __sco_sock_close(sk);
 
-               if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime)
+               if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime &&
+                   !(current->flags & PF_EXITING))
                        err = bt_sock_wait_state(sk, BT_CLOSED,
                                                 sk->sk_lingertime);
        }
@@ -954,7 +991,8 @@ static int sco_sock_release(struct socket *sock)
 
        sco_sock_close(sk);
 
-       if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime) {
+       if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime &&
+           !(current->flags & PF_EXITING)) {
                lock_sock(sk);
                err = bt_sock_wait_state(sk, BT_CLOSED, sk->sk_lingertime);
                release_sock(sk);
@@ -965,44 +1003,6 @@ static int sco_sock_release(struct socket *sock)
        return err;
 }
 
-static void __sco_chan_add(struct sco_conn *conn, struct sock *sk, struct sock *parent)
-{
-       BT_DBG("conn %p", conn);
-
-       sco_pi(sk)->conn = conn;
-       conn->sk = sk;
-
-       if (parent)
-               bt_accept_enqueue(parent, sk);
-}
-
-/* Delete channel.
- * Must be called on the locked socket. */
-static void sco_chan_del(struct sock *sk, int err)
-{
-       struct sco_conn *conn;
-
-       conn = sco_pi(sk)->conn;
-
-       BT_DBG("sk %p, conn %p, err %d", sk, conn, err);
-
-       if (conn) {
-               sco_conn_lock(conn);
-               conn->sk = NULL;
-               sco_pi(sk)->conn = NULL;
-               sco_conn_unlock(conn);
-
-               if (conn->hcon)
-                       hci_conn_drop(conn->hcon);
-       }
-
-       sk->sk_state = BT_CLOSED;
-       sk->sk_err   = err;
-       sk->sk_state_change(sk);
-
-       sock_set_flag(sk, SOCK_ZAPPED);
-}
-
 static void sco_conn_ready(struct sco_conn *conn)
 {
        struct sock *parent;