Merge tag 'v3.10.55' into update
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / net / bluetooth / sco.c
index fb6192c9812e81bcac3d8dea31f60095aa40ffda..de9c955b247acb7ccf1b4efc0a67dd9819502643 100644 (file)
@@ -83,7 +83,7 @@ static struct sco_conn *sco_conn_add(struct hci_conn *hcon)
        if (conn)
                return conn;
 
-       conn = kzalloc(sizeof(struct sco_conn), GFP_ATOMIC);
+       conn = kzalloc(sizeof(struct sco_conn), GFP_KERNEL);
        if (!conn)
                return NULL;
 
@@ -158,6 +158,7 @@ static int sco_connect(struct sock *sk)
 {
        bdaddr_t *src = &bt_sk(sk)->src;
        bdaddr_t *dst = &bt_sk(sk)->dst;
+       __u16 pkt_type = sco_pi(sk)->pkt_type;
        struct sco_conn *conn;
        struct hci_conn *hcon;
        struct hci_dev  *hdev;
@@ -173,11 +174,13 @@ static int sco_connect(struct sock *sk)
 
        if (lmp_esco_capable(hdev) && !disable_esco)
                type = ESCO_LINK;
-       else
+       else {
                type = SCO_LINK;
+               pkt_type &= SCO_ESCO_MASK;
+       }
 
-       hcon = hci_connect(hdev, type, dst, BDADDR_BREDR, BT_SECURITY_LOW,
-                          HCI_AT_NO_BONDING);
+       hcon = hci_connect(hdev, type, pkt_type, dst, BDADDR_BREDR,
+                          BT_SECURITY_LOW, HCI_AT_NO_BONDING);
        if (IS_ERR(hcon)) {
                err = PTR_ERR(hcon);
                goto done;
@@ -185,7 +188,7 @@ static int sco_connect(struct sock *sk)
 
        conn = sco_conn_add(hcon);
        if (!conn) {
-               hci_conn_put(hcon);
+               hci_conn_drop(hcon);
                err = -ENOMEM;
                goto done;
        }
@@ -353,7 +356,7 @@ 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);
-                       hci_conn_put(sco_pi(sk)->conn->hcon);
+                       hci_conn_drop(sco_pi(sk)->conn->hcon);
                        sco_pi(sk)->conn->hcon = NULL;
                } else
                        sco_chan_del(sk, ECONNRESET);
@@ -445,17 +448,21 @@ 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 alen)
 {
-       struct sockaddr_sco *sa = (struct sockaddr_sco *) addr;
+       struct sockaddr_sco sa;
        struct sock *sk = sock->sk;
-       int err = 0;
+       int len, err = 0;
 
-       BT_DBG("sk %p %pMR", sk, &sa->sco_bdaddr);
+       BT_DBG("sk %p %pMR", sk, &sa.sco_bdaddr);
 
        if (!addr || addr->sa_family != AF_BLUETOOTH)
                return -EINVAL;
 
+       memset(&sa, 0, sizeof(sa));
+       len = min_t(unsigned int, sizeof(sa), alen);
+       memcpy(&sa, addr, len);
+
        lock_sock(sk);
 
        if (sk->sk_state != BT_OPEN) {
@@ -468,7 +475,8 @@ static int sco_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_le
                goto done;
        }
 
-       bacpy(&bt_sk(sk)->src, &sa->sco_bdaddr);
+       bacpy(&bt_sk(sk)->src, &sa.sco_bdaddr);
+       sco_pi(sk)->pkt_type = sa.sco_pkt_type;
 
        sk->sk_state = BT_BOUND;
 
@@ -479,27 +487,34 @@ done:
 
 static int sco_sock_connect(struct socket *sock, struct sockaddr *addr, int alen, int flags)
 {
-       struct sockaddr_sco *sa = (struct sockaddr_sco *) addr;
        struct sock *sk = sock->sk;
-       int err = 0;
-
+       struct sockaddr_sco sa;
+       int len, err;
 
        BT_DBG("sk %p", sk);
 
-       if (alen < sizeof(struct sockaddr_sco) ||
-           addr->sa_family != AF_BLUETOOTH)
+       if (!addr || addr->sa_family != AF_BLUETOOTH)
                return -EINVAL;
 
-       if (sk->sk_state != BT_OPEN && sk->sk_state != BT_BOUND)
-               return -EBADFD;
-
-       if (sk->sk_type != SOCK_SEQPACKET)
-               return -EINVAL;
+       memset(&sa, 0, sizeof(sa));
+       len = min_t(unsigned int, sizeof(sa), alen);
+       memcpy(&sa, addr, len);
 
        lock_sock(sk);
 
+       if (sk->sk_type != SOCK_SEQPACKET) {
+               err = -EINVAL;
+               goto done;
+       }
+
+       if (sk->sk_state != BT_OPEN && sk->sk_state != BT_BOUND) {
+               err = -EBADFD;
+               goto done;
+       }
+
        /* Set destination address and psm */
-       bacpy(&bt_sk(sk)->dst, &sa->sco_bdaddr);
+       bacpy(&bt_sk(sk)->dst, &sa.sco_bdaddr);
+       sco_pi(sk)->pkt_type = sa.sco_pkt_type;
 
        err = sco_connect(sk);
        if (err)
@@ -623,6 +638,7 @@ static int sco_sock_getname(struct socket *sock, struct sockaddr *addr, int *len
                bacpy(&sa->sco_bdaddr, &bt_sk(sk)->dst);
        else
                bacpy(&sa->sco_bdaddr, &bt_sk(sk)->src);
+       sa->sco_pkt_type = sco_pi(sk)->pkt_type;
 
        return 0;
 }
@@ -653,6 +669,42 @@ static int sco_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
        return err;
 }
 
+static void sco_conn_defer_accept(struct hci_conn *conn, int mask)
+{
+       struct hci_dev *hdev = conn->hdev;
+
+       BT_DBG("conn %p", conn);
+
+       conn->state = BT_CONFIG;
+
+       if (!lmp_esco_capable(hdev)) {
+               struct hci_cp_accept_conn_req cp;
+
+               bacpy(&cp.bdaddr, &conn->dst);
+
+               if (lmp_rswitch_capable(hdev) && (mask & HCI_LM_MASTER))
+                       cp.role = 0x00; /* Become master */
+               else
+                       cp.role = 0x01; /* Remain slave */
+
+               hci_send_cmd(hdev, HCI_OP_ACCEPT_CONN_REQ, sizeof(cp), &cp);
+       } else {
+               struct hci_cp_accept_sync_conn_req cp;
+
+               bacpy(&cp.bdaddr, &conn->dst);
+               cp.pkt_type = cpu_to_le16(conn->pkt_type);
+
+               cp.tx_bandwidth   = __constant_cpu_to_le32(0x00001f40);
+               cp.rx_bandwidth   = __constant_cpu_to_le32(0x00001f40);
+               cp.max_latency    = __constant_cpu_to_le16(0xffff);
+               cp.content_format = cpu_to_le16(hdev->voice_setting);
+               cp.retrans_effort = 0xff;
+
+               hci_send_cmd(hdev, HCI_OP_ACCEPT_SYNC_CONN_REQ,
+                            sizeof(cp), &cp);
+       }
+}
+
 static int sco_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
                            struct msghdr *msg, size_t len, int flags)
 {
@@ -663,9 +715,8 @@ static int sco_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
 
        if (sk->sk_state == BT_CONNECT2 &&
            test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags)) {
-               hci_conn_accept(pi->conn->hcon, 0);
+               sco_conn_defer_accept(pi->conn->hcon, 0);
                sk->sk_state = BT_CONFIG;
-               msg->msg_namelen = 0;
 
                release_sock(sk);
                return 0;
@@ -824,7 +875,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);
        }
@@ -844,7 +896,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);
@@ -883,7 +936,7 @@ static void sco_chan_del(struct sock *sk, int err)
                sco_conn_unlock(conn);
 
                if (conn->hcon)
-                       hci_conn_put(conn->hcon);
+                       hci_conn_drop(conn->hcon);
        }
 
        sk->sk_state = BT_CLOSED;
@@ -1084,7 +1137,7 @@ int __init sco_init(void)
                goto error;
        }
 
-       err = bt_procfs_init(THIS_MODULE, &init_net, "sco", &sco_sk_list, NULL);
+       err = bt_procfs_init(&init_net, "sco", &sco_sk_list, NULL);
        if (err < 0) {
                BT_ERR("Failed to create SCO proc file");
                bt_sock_unregister(BTPROTO_SCO);
@@ -1113,8 +1166,7 @@ void __exit sco_exit(void)
 
        debugfs_remove(sco_debugfs);
 
-       if (bt_sock_unregister(BTPROTO_SCO) < 0)
-               BT_ERR("SCO socket unregistration failed");
+       bt_sock_unregister(BTPROTO_SCO);
 
        proto_unregister(&sco_proto);
 }