These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / net / bluetooth / sco.c
index 4322c83..f52bcbf 100644 (file)
@@ -74,7 +74,7 @@ struct sco_pinfo {
 
 static void sco_sock_timeout(unsigned long arg)
 {
-       struct sock *sk = (struct sock *) arg;
+       struct sock *sk = (struct sock *)arg;
 
        BT_DBG("sock %p state %d", sk, sk->sk_state);
 
@@ -154,13 +154,13 @@ static void sco_chan_del(struct sock *sk, int err)
        sock_set_flag(sk, SOCK_ZAPPED);
 }
 
-static int sco_conn_del(struct hci_conn *hcon, int err)
+static void sco_conn_del(struct hci_conn *hcon, int err)
 {
        struct sco_conn *conn = hcon->sco_data;
        struct sock *sk;
 
        if (!conn)
-               return 0;
+               return;
 
        BT_DBG("hcon %p conn %p, err %d", hcon, conn, err);
 
@@ -170,19 +170,21 @@ static int sco_conn_del(struct hci_conn *hcon, int err)
        sco_conn_unlock(conn);
 
        if (sk) {
+               sock_hold(sk);
                bh_lock_sock(sk);
                sco_sock_clear_timer(sk);
                sco_chan_del(sk, err);
                bh_unlock_sock(sk);
                sco_sock_kill(sk);
+               sock_put(sk);
        }
 
        hcon->sco_data = NULL;
        kfree(conn);
-       return 0;
 }
 
-static void __sco_chan_add(struct sco_conn *conn, struct sock *sk, struct sock *parent)
+static void __sco_chan_add(struct sco_conn *conn, struct sock *sk,
+                          struct sock *parent)
 {
        BT_DBG("conn %p", conn);
 
@@ -415,8 +417,10 @@ static void __sco_sock_close(struct sock *sk)
                if (sco_pi(sk)->conn->hcon) {
                        sk->sk_state = BT_DISCONN;
                        sco_sock_set_timer(sk, SCO_DISCONN_TIMEOUT);
+                       sco_conn_lock(sco_pi(sk)->conn);
                        hci_conn_drop(sco_pi(sk)->conn->hcon);
                        sco_pi(sk)->conn->hcon = NULL;
+                       sco_conn_unlock(sco_pi(sk)->conn);
                } else
                        sco_chan_del(sk, ECONNRESET);
                break;
@@ -460,11 +464,12 @@ static struct proto sco_proto = {
        .obj_size       = sizeof(struct sco_pinfo)
 };
 
-static struct sock *sco_sock_alloc(struct net *net, struct socket *sock, int proto, gfp_t prio)
+static struct sock *sco_sock_alloc(struct net *net, struct socket *sock,
+                                  int proto, gfp_t prio, int kern)
 {
        struct sock *sk;
 
-       sk = sk_alloc(net, PF_BLUETOOTH, prio, &sco_proto);
+       sk = sk_alloc(net, PF_BLUETOOTH, prio, &sco_proto, kern);
        if (!sk)
                return NULL;
 
@@ -501,7 +506,7 @@ static int sco_sock_create(struct net *net, struct socket *sock, int protocol,
 
        sock->ops = &sco_sock_ops;
 
-       sk = sco_sock_alloc(net, sock, protocol, GFP_ATOMIC);
+       sk = sco_sock_alloc(net, sock, protocol, GFP_ATOMIC, kern);
        if (!sk)
                return -ENOMEM;
 
@@ -509,7 +514,8 @@ static int sco_sock_create(struct net *net, struct socket *sock, int protocol,
        return 0;
 }
 
-static int sco_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_len)
+static int sco_sock_bind(struct socket *sock, struct sockaddr *addr,
+                        int addr_len)
 {
        struct sockaddr_sco *sa = (struct sockaddr_sco *) addr;
        struct sock *sk = sock->sk;
@@ -520,6 +526,9 @@ static int sco_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_le
        if (!addr || addr->sa_family != AF_BLUETOOTH)
                return -EINVAL;
 
+       if (addr_len < sizeof(struct sockaddr_sco))
+               return -EINVAL;
+
        lock_sock(sk);
 
        if (sk->sk_state != BT_OPEN) {
@@ -616,7 +625,8 @@ done:
        return err;
 }
 
-static int sco_sock_accept(struct socket *sock, struct socket *newsock, int flags)
+static int sco_sock_accept(struct socket *sock, struct socket *newsock,
+                          int flags)
 {
        DEFINE_WAIT_FUNC(wait, woken_wake_function);
        struct sock *sk = sock->sk, *ch;
@@ -670,7 +680,8 @@ done:
        return err;
 }
 
-static int sco_sock_getname(struct socket *sock, struct sockaddr *addr, int *len, int peer)
+static int sco_sock_getname(struct socket *sock, struct sockaddr *addr,
+                           int *len, int peer)
 {
        struct sockaddr_sco *sa = (struct sockaddr_sco *) addr;
        struct sock *sk = sock->sk;
@@ -780,7 +791,8 @@ static int sco_sock_recvmsg(struct socket *sock, struct msghdr *msg,
        return bt_sock_recvmsg(sock, msg, len, flags);
 }
 
-static int sco_sock_setsockopt(struct socket *sock, int level, int optname, char __user *optval, unsigned int optlen)
+static int sco_sock_setsockopt(struct socket *sock, int level, int optname,
+                              char __user *optval, unsigned int optlen)
 {
        struct sock *sk = sock->sk;
        int len, err = 0;
@@ -820,7 +832,7 @@ static int sco_sock_setsockopt(struct socket *sock, int level, int optname, char
                voice.setting = sco_pi(sk)->setting;
 
                len = min_t(unsigned int, sizeof(voice), optlen);
-               if (copy_from_user((char *) &voice, optval, len)) {
+               if (copy_from_user((char *)&voice, optval, len)) {
                        err = -EFAULT;
                        break;
                }
@@ -844,7 +856,8 @@ static int sco_sock_setsockopt(struct socket *sock, int level, int optname, char
        return err;
 }
 
-static int sco_sock_getsockopt_old(struct socket *sock, int optname, char __user *optval, int __user *optlen)
+static int sco_sock_getsockopt_old(struct socket *sock, int optname,
+                                  char __user *optval, int __user *optlen)
 {
        struct sock *sk = sock->sk;
        struct sco_options opts;
@@ -904,7 +917,8 @@ static int sco_sock_getsockopt_old(struct socket *sock, int optname, char __user
        return err;
 }
 
-static int sco_sock_getsockopt(struct socket *sock, int level, int optname, char __user *optval, int __user *optlen)
+static int sco_sock_getsockopt(struct socket *sock, int level, int optname,
+                              char __user *optval, int __user *optlen)
 {
        struct sock *sk = sock->sk;
        int len, err = 0;
@@ -929,7 +943,7 @@ static int sco_sock_getsockopt(struct socket *sock, int level, int optname, char
                }
 
                if (put_user(test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags),
-                            (u32 __user *) optval))
+                            (u32 __user *)optval))
                        err = -EFAULT;
 
                break;
@@ -962,7 +976,9 @@ static int sco_sock_shutdown(struct socket *sock, int how)
        if (!sk)
                return 0;
 
+       sock_hold(sk);
        lock_sock(sk);
+
        if (!sk->sk_shutdown) {
                sk->sk_shutdown = SHUTDOWN_MASK;
                sco_sock_clear_timer(sk);
@@ -973,7 +989,10 @@ static int sco_sock_shutdown(struct socket *sock, int how)
                        err = bt_sock_wait_state(sk, BT_CLOSED,
                                                 sk->sk_lingertime);
        }
+
        release_sock(sk);
+       sock_put(sk);
+
        return err;
 }
 
@@ -1017,6 +1036,11 @@ static void sco_conn_ready(struct sco_conn *conn)
        } else {
                sco_conn_lock(conn);
 
+               if (!conn->hcon) {
+                       sco_conn_unlock(conn);
+                       return;
+               }
+
                parent = sco_get_sock_listen(&conn->hcon->src);
                if (!parent) {
                        sco_conn_unlock(conn);
@@ -1026,7 +1050,7 @@ static void sco_conn_ready(struct sco_conn *conn)
                bh_lock_sock(parent);
 
                sk = sco_sock_alloc(sock_net(parent), NULL,
-                                   BTPROTO_SCO, GFP_ATOMIC);
+                                   BTPROTO_SCO, GFP_ATOMIC, 0);
                if (!sk) {
                        bh_unlock_sock(parent);
                        sco_conn_unlock(conn);
@@ -1110,7 +1134,7 @@ static void sco_disconn_cfm(struct hci_conn *hcon, __u8 reason)
        sco_conn_del(hcon, bt_to_errno(reason));
 }
 
-int sco_recv_scodata(struct hci_conn *hcon, struct sk_buff *skb)
+void sco_recv_scodata(struct hci_conn *hcon, struct sk_buff *skb)
 {
        struct sco_conn *conn = hcon->sco_data;
 
@@ -1121,12 +1145,11 @@ int sco_recv_scodata(struct hci_conn *hcon, struct sk_buff *skb)
 
        if (skb->len) {
                sco_recv_frame(conn, skb);
-               return 0;
+               return;
        }
 
 drop:
        kfree_skb(skb);
-       return 0;
 }
 
 static struct hci_cb sco_cb = {